From 35f79094e9983bf13ab720eb7b30c16e34890919 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 18 Dec 2021 10:18:29 -0800 Subject: [PATCH] Add tests --- .../dependentDestructuredVariables.js | 114 ++++++++++ .../dependentDestructuredVariables.symbols | 161 ++++++++++++++ .../dependentDestructuredVariables.types | 206 ++++++++++++++++++ .../dependentDestructuredVariables.ts | 58 +++++ 4 files changed, 539 insertions(+) diff --git a/tests/baselines/reference/dependentDestructuredVariables.js b/tests/baselines/reference/dependentDestructuredVariables.js index ac99a33df54bd..2eb7be3d946a4 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.js +++ b/tests/baselines/reference/dependentDestructuredVariables.js @@ -167,6 +167,64 @@ const { value, done } = it.next(); if (!done) { value; // number } + +// Repro from #46658 + +declare function f50(cb: (...args: Args) => void): void + +f50((kind, data) => { + if (kind === 'A') { + data.toFixed(); + } + if (kind === 'B') { + data.toUpperCase(); + } +}); + +const f51: (...args: ['A', number] | ['B', string]) => void = (kind, payload) => { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +}; + +const f52: (...args: ['A', number] | ['B']) => void = (kind, payload?) => { + if (kind === 'A') { + payload.toFixed(); + } + else { + payload; // undefined + } +}; + +declare function readFile(path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void): void; + +readFile('hello', (err, data) => { + if (err === null) { + data.length; + } + else { + err.message; + } +}); + +type ReducerArgs = ["add", { a: number, b: number }] | ["concat", { firstArr: any[], secondArr: any[] }]; + +const reducer: (...args: ReducerArgs) => void = (op, args) => { + switch (op) { + case "add": + console.log(args.a + args.b); + break; + case "concat": + console.log(args.firstArr.concat(args.secondArr)); + break; + } +} + +reducer("add", { a: 1, b: 3 }); +reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }); //// [dependentDestructuredVariables.js] @@ -292,6 +350,50 @@ const { value, done } = it.next(); if (!done) { value; // number } +f50((kind, data) => { + if (kind === 'A') { + data.toFixed(); + } + if (kind === 'B') { + data.toUpperCase(); + } +}); +const f51 = (kind, payload) => { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +}; +const f52 = (kind, payload) => { + if (kind === 'A') { + payload.toFixed(); + } + else { + payload; // undefined + } +}; +readFile('hello', (err, data) => { + if (err === null) { + data.length; + } + else { + err.message; + } +}); +const reducer = (op, args) => { + switch (op) { + case "add": + console.log(args.a + args.b); + break; + case "concat": + console.log(args.firstArr.concat(args.secondArr)); + break; + } +}; +reducer("add", { a: 1, b: 3 }); +reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }); //// [dependentDestructuredVariables.d.ts] @@ -355,3 +457,15 @@ declare type Action3 = { declare const reducerBroken: (state: number, { type, payload }: Action3) => number; declare var it: Iterator; declare const value: any, done: boolean | undefined; +declare function f50(cb: (...args: Args) => void): void; +declare const f51: (...args: ['A', number] | ['B', string]) => void; +declare const f52: (...args: ['A', number] | ['B']) => void; +declare function readFile(path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void): void; +declare type ReducerArgs = ["add", { + a: number; + b: number; +}] | ["concat", { + firstArr: any[]; + secondArr: any[]; +}]; +declare const reducer: (...args: ReducerArgs) => void; diff --git a/tests/baselines/reference/dependentDestructuredVariables.symbols b/tests/baselines/reference/dependentDestructuredVariables.symbols index 7c8d0649bf018..bad7fbf5b690e 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.symbols +++ b/tests/baselines/reference/dependentDestructuredVariables.symbols @@ -434,3 +434,164 @@ if (!done) { >value : Symbol(value, Decl(dependentDestructuredVariables.ts, 164, 7)) } +// Repro from #46658 + +declare function f50(cb: (...args: Args) => void): void +>f50 : Symbol(f50, Decl(dependentDestructuredVariables.ts, 167, 1)) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 171, 21)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 171, 26)) +>Args : Symbol(Args, Decl(dependentDestructuredVariables.ts, 111, 1)) + +f50((kind, data) => { +>f50 : Symbol(f50, Decl(dependentDestructuredVariables.ts, 167, 1)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 173, 5)) +>data : Symbol(data, Decl(dependentDestructuredVariables.ts, 173, 10)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 173, 5)) + + data.toFixed(); +>data.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>data : Symbol(data, Decl(dependentDestructuredVariables.ts, 173, 10)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + } + if (kind === 'B') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 173, 5)) + + data.toUpperCase(); +>data.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>data : Symbol(data, Decl(dependentDestructuredVariables.ts, 173, 10)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } +}); + +const f51: (...args: ['A', number] | ['B', string]) => void = (kind, payload) => { +>f51 : Symbol(f51, Decl(dependentDestructuredVariables.ts, 182, 5)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 182, 12)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 182, 63)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 182, 68)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 182, 63)) + + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 182, 68)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + } + if (kind === 'B') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 182, 63)) + + payload.toUpperCase(); +>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 182, 68)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } +}; + +const f52: (...args: ['A', number] | ['B']) => void = (kind, payload?) => { +>f52 : Symbol(f52, Decl(dependentDestructuredVariables.ts, 191, 5)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 191, 12)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 191, 55)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 191, 60)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 191, 55)) + + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 191, 60)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + } + else { + payload; // undefined +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 191, 60)) + } +}; + +declare function readFile(path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void): void; +>readFile : Symbol(readFile, Decl(dependentDestructuredVariables.ts, 198, 2)) +>path : Symbol(path, Decl(dependentDestructuredVariables.ts, 200, 26)) +>callback : Symbol(callback, Decl(dependentDestructuredVariables.ts, 200, 39)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 200, 51)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +readFile('hello', (err, data) => { +>readFile : Symbol(readFile, Decl(dependentDestructuredVariables.ts, 198, 2)) +>err : Symbol(err, Decl(dependentDestructuredVariables.ts, 202, 19)) +>data : Symbol(data, Decl(dependentDestructuredVariables.ts, 202, 23)) + + if (err === null) { +>err : Symbol(err, Decl(dependentDestructuredVariables.ts, 202, 19)) + + data.length; +>data.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>data : Symbol(data, Decl(dependentDestructuredVariables.ts, 202, 23)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + } + else { + err.message; +>err.message : Symbol(Error.message, Decl(lib.es5.d.ts, --, --)) +>err : Symbol(err, Decl(dependentDestructuredVariables.ts, 202, 19)) +>message : Symbol(Error.message, Decl(lib.es5.d.ts, --, --)) + } +}); + +type ReducerArgs = ["add", { a: number, b: number }] | ["concat", { firstArr: any[], secondArr: any[] }]; +>ReducerArgs : Symbol(ReducerArgs, Decl(dependentDestructuredVariables.ts, 209, 3)) +>a : Symbol(a, Decl(dependentDestructuredVariables.ts, 211, 28)) +>b : Symbol(b, Decl(dependentDestructuredVariables.ts, 211, 39)) +>firstArr : Symbol(firstArr, Decl(dependentDestructuredVariables.ts, 211, 67)) +>secondArr : Symbol(secondArr, Decl(dependentDestructuredVariables.ts, 211, 84)) + +const reducer: (...args: ReducerArgs) => void = (op, args) => { +>reducer : Symbol(reducer, Decl(dependentDestructuredVariables.ts, 213, 5)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 213, 16)) +>ReducerArgs : Symbol(ReducerArgs, Decl(dependentDestructuredVariables.ts, 209, 3)) +>op : Symbol(op, Decl(dependentDestructuredVariables.ts, 213, 49)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 213, 52)) + + switch (op) { +>op : Symbol(op, Decl(dependentDestructuredVariables.ts, 213, 49)) + + case "add": + console.log(args.a + args.b); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>args.a : Symbol(a, Decl(dependentDestructuredVariables.ts, 211, 28)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 213, 52)) +>a : Symbol(a, Decl(dependentDestructuredVariables.ts, 211, 28)) +>args.b : Symbol(b, Decl(dependentDestructuredVariables.ts, 211, 39)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 213, 52)) +>b : Symbol(b, Decl(dependentDestructuredVariables.ts, 211, 39)) + + break; + case "concat": + console.log(args.firstArr.concat(args.secondArr)); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>args.firstArr.concat : Symbol(Array.concat, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>args.firstArr : Symbol(firstArr, Decl(dependentDestructuredVariables.ts, 211, 67)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 213, 52)) +>firstArr : Symbol(firstArr, Decl(dependentDestructuredVariables.ts, 211, 67)) +>concat : Symbol(Array.concat, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>args.secondArr : Symbol(secondArr, Decl(dependentDestructuredVariables.ts, 211, 84)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 213, 52)) +>secondArr : Symbol(secondArr, Decl(dependentDestructuredVariables.ts, 211, 84)) + + break; + } +} + +reducer("add", { a: 1, b: 3 }); +>reducer : Symbol(reducer, Decl(dependentDestructuredVariables.ts, 213, 5)) +>a : Symbol(a, Decl(dependentDestructuredVariables.ts, 224, 16)) +>b : Symbol(b, Decl(dependentDestructuredVariables.ts, 224, 22)) + +reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }); +>reducer : Symbol(reducer, Decl(dependentDestructuredVariables.ts, 213, 5)) +>firstArr : Symbol(firstArr, Decl(dependentDestructuredVariables.ts, 225, 19)) +>secondArr : Symbol(secondArr, Decl(dependentDestructuredVariables.ts, 225, 37)) + diff --git a/tests/baselines/reference/dependentDestructuredVariables.types b/tests/baselines/reference/dependentDestructuredVariables.types index de8851a3661db..a1b16d186ee08 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.types +++ b/tests/baselines/reference/dependentDestructuredVariables.types @@ -471,3 +471,209 @@ if (!done) { >value : number } +// Repro from #46658 + +declare function f50(cb: (...args: Args) => void): void +>f50 : (cb: (...args: Args) => void) => void +>cb : (...args: Args) => void +>args : Args + +f50((kind, data) => { +>f50((kind, data) => { if (kind === 'A') { data.toFixed(); } if (kind === 'B') { data.toUpperCase(); }}) : void +>f50 : (cb: (...args: Args) => void) => void +>(kind, data) => { if (kind === 'A') { data.toFixed(); } if (kind === 'B') { data.toUpperCase(); }} : (kind: "A" | "B", data: string | number) => void +>kind : "A" | "B" +>data : string | number + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" +>'A' : "A" + + data.toFixed(); +>data.toFixed() : string +>data.toFixed : (fractionDigits?: number | undefined) => string +>data : number +>toFixed : (fractionDigits?: number | undefined) => string + } + if (kind === 'B') { +>kind === 'B' : boolean +>kind : "A" | "B" +>'B' : "B" + + data.toUpperCase(); +>data.toUpperCase() : string +>data.toUpperCase : () => string +>data : string +>toUpperCase : () => string + } +}); + +const f51: (...args: ['A', number] | ['B', string]) => void = (kind, payload) => { +>f51 : (...args: ['A', number] | ['B', string]) => void +>args : ["A", number] | ["B", string] +>(kind, payload) => { if (kind === 'A') { payload.toFixed(); } if (kind === 'B') { payload.toUpperCase(); }} : (kind: "A" | "B", payload: string | number) => void +>kind : "A" | "B" +>payload : string | number + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + } + if (kind === 'B') { +>kind === 'B' : boolean +>kind : "A" | "B" +>'B' : "B" + + payload.toUpperCase(); +>payload.toUpperCase() : string +>payload.toUpperCase : () => string +>payload : string +>toUpperCase : () => string + } +}; + +const f52: (...args: ['A', number] | ['B']) => void = (kind, payload?) => { +>f52 : (...args: ['A', number] | ['B']) => void +>args : ["A", number] | ["B"] +>(kind, payload?) => { if (kind === 'A') { payload.toFixed(); } else { payload; // undefined }} : (kind: "A" | "B", payload?: number | undefined) => void +>kind : "A" | "B" +>payload : number | undefined + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + } + else { + payload; // undefined +>payload : undefined + } +}; + +declare function readFile(path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void): void; +>readFile : (path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void) => void +>path : string +>callback : (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void +>args : [err: null, data: unknown[]] | [err: Error, data: undefined] +>null : null + +readFile('hello', (err, data) => { +>readFile('hello', (err, data) => { if (err === null) { data.length; } else { err.message; }}) : void +>readFile : (path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void) => void +>'hello' : "hello" +>(err, data) => { if (err === null) { data.length; } else { err.message; }} : (err: Error | null, data: unknown[] | undefined) => void +>err : Error | null +>data : unknown[] | undefined + + if (err === null) { +>err === null : boolean +>err : Error | null +>null : null + + data.length; +>data.length : number +>data : unknown[] +>length : number + } + else { + err.message; +>err.message : string +>err : Error +>message : string + } +}); + +type ReducerArgs = ["add", { a: number, b: number }] | ["concat", { firstArr: any[], secondArr: any[] }]; +>ReducerArgs : ReducerArgs +>a : number +>b : number +>firstArr : any[] +>secondArr : any[] + +const reducer: (...args: ReducerArgs) => void = (op, args) => { +>reducer : (...args: ReducerArgs) => void +>args : ReducerArgs +>(op, args) => { switch (op) { case "add": console.log(args.a + args.b); break; case "concat": console.log(args.firstArr.concat(args.secondArr)); break; }} : (op: "add" | "concat", args: { a: number; b: number; } | { firstArr: any[]; secondArr: any[]; }) => void +>op : "add" | "concat" +>args : { a: number; b: number; } | { firstArr: any[]; secondArr: any[]; } + + switch (op) { +>op : "add" | "concat" + + case "add": +>"add" : "add" + + console.log(args.a + args.b); +>console.log(args.a + args.b) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>args.a + args.b : number +>args.a : number +>args : { a: number; b: number; } +>a : number +>args.b : number +>args : { a: number; b: number; } +>b : number + + break; + case "concat": +>"concat" : "concat" + + console.log(args.firstArr.concat(args.secondArr)); +>console.log(args.firstArr.concat(args.secondArr)) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>args.firstArr.concat(args.secondArr) : any[] +>args.firstArr.concat : { (...items: ConcatArray[]): any[]; (...items: any[]): any[]; } +>args.firstArr : any[] +>args : { firstArr: any[]; secondArr: any[]; } +>firstArr : any[] +>concat : { (...items: ConcatArray[]): any[]; (...items: any[]): any[]; } +>args.secondArr : any[] +>args : { firstArr: any[]; secondArr: any[]; } +>secondArr : any[] + + break; + } +} + +reducer("add", { a: 1, b: 3 }); +>reducer("add", { a: 1, b: 3 }) : void +>reducer : (...args: ReducerArgs) => void +>"add" : "add" +>{ a: 1, b: 3 } : { a: number; b: number; } +>a : number +>1 : 1 +>b : number +>3 : 3 + +reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }); +>reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }) : void +>reducer : (...args: ReducerArgs) => void +>"concat" : "concat" +>{ firstArr: [1, 2], secondArr: [3, 4] } : { firstArr: number[]; secondArr: number[]; } +>firstArr : number[] +>[1, 2] : number[] +>1 : 1 +>2 : 2 +>secondArr : number[] +>[3, 4] : number[] +>3 : 3 +>4 : 4 + diff --git a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts index c7a3f911acbfc..38bcb68d048e8 100644 --- a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts +++ b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts @@ -170,3 +170,61 @@ const { value, done } = it.next(); if (!done) { value; // number } + +// Repro from #46658 + +declare function f50(cb: (...args: Args) => void): void + +f50((kind, data) => { + if (kind === 'A') { + data.toFixed(); + } + if (kind === 'B') { + data.toUpperCase(); + } +}); + +const f51: (...args: ['A', number] | ['B', string]) => void = (kind, payload) => { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +}; + +const f52: (...args: ['A', number] | ['B']) => void = (kind, payload?) => { + if (kind === 'A') { + payload.toFixed(); + } + else { + payload; // undefined + } +}; + +declare function readFile(path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void): void; + +readFile('hello', (err, data) => { + if (err === null) { + data.length; + } + else { + err.message; + } +}); + +type ReducerArgs = ["add", { a: number, b: number }] | ["concat", { firstArr: any[], secondArr: any[] }]; + +const reducer: (...args: ReducerArgs) => void = (op, args) => { + switch (op) { + case "add": + console.log(args.a + args.b); + break; + case "concat": + console.log(args.firstArr.concat(args.secondArr)); + break; + } +} + +reducer("add", { a: 1, b: 3 }); +reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });