Fix/dependent parameters obj methods (#48110)

* Add failing test for dependent destructured variables within obj methods

* Fixed an issue with dependent parameters within obj methods
This commit is contained in:
Mateusz Burzyński
2022-03-11 18:46:30 +01:00
committed by GitHub
parent 5fd0b6432e
commit 04238e6f52
5 changed files with 585 additions and 4 deletions

View File

@@ -24471,7 +24471,7 @@ namespace ts {
}
function getCandidateDiscriminantPropertyAccess(expr: Expression) {
if (isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference)) {
if (isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) || isObjectLiteralMethod(reference)) {
// When the reference is a binding pattern or function or arrow expression, we are narrowing a pesudo-reference in
// getNarrowedTypeOfSymbol. An identifier for a destructuring variable declared in the same binding pattern or
// parameter declared in the same parameter list is a candidate.

View File

@@ -225,10 +225,101 @@ const reducer: (...args: ReducerArgs) => void = (op, args) => {
reducer("add", { a: 1, b: 3 });
reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });
// repro from https://github.com/microsoft/TypeScript/pull/47190#issuecomment-1057603588
type FooMethod = {
method(...args:
[type: "str", cb: (e: string) => void] |
[type: "num", cb: (e: number) => void]
): void;
}
let fooM: FooMethod = {
method(type, cb) {
if (type == 'num') {
cb(123)
} else {
cb("abc")
}
}
};
type FooAsyncMethod = {
method(...args:
[type: "str", cb: (e: string) => void] |
[type: "num", cb: (e: number) => void]
): Promise<any>;
}
let fooAsyncM: FooAsyncMethod = {
async method(type, cb) {
if (type == 'num') {
cb(123)
} else {
cb("abc")
}
}
};
type FooGenMethod = {
method(...args:
[type: "str", cb: (e: string) => void] |
[type: "num", cb: (e: number) => void]
): Generator<any, any, any>;
}
let fooGenM: FooGenMethod = {
*method(type, cb) {
if (type == 'num') {
cb(123)
} else {
cb("abc")
}
}
};
type FooAsyncGenMethod = {
method(...args:
[type: "str", cb: (e: string) => void] |
[type: "num", cb: (e: number) => void]
): AsyncGenerator<any, any, any>;
}
let fooAsyncGenM: FooAsyncGenMethod = {
async *method(type, cb) {
if (type == 'num') {
cb(123)
} else {
cb("abc")
}
}
};
//// [dependentDestructuredVariables.js]
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
function f10({ kind, payload }) {
if (kind === 'A') {
payload.toFixed();
@@ -394,6 +485,50 @@ const reducer = (op, args) => {
};
reducer("add", { a: 1, b: 3 });
reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });
let fooM = {
method(type, cb) {
if (type == 'num') {
cb(123);
}
else {
cb("abc");
}
}
};
let fooAsyncM = {
method(type, cb) {
return __awaiter(this, void 0, void 0, function* () {
if (type == 'num') {
cb(123);
}
else {
cb("abc");
}
});
}
};
let fooGenM = {
*method(type, cb) {
if (type == 'num') {
cb(123);
}
else {
cb("abc");
}
}
};
let fooAsyncGenM = {
method(type, cb) {
return __asyncGenerator(this, arguments, function* method_1() {
if (type == 'num') {
cb(123);
}
else {
cb("abc");
}
});
}
};
//// [dependentDestructuredVariables.d.ts]
@@ -469,3 +604,43 @@ declare type ReducerArgs = ["add", {
secondArr: any[];
}];
declare const reducer: (...args: ReducerArgs) => void;
declare type FooMethod = {
method(...args: [
type: "str",
cb: (e: string) => void
] | [
type: "num",
cb: (e: number) => void
]): void;
};
declare let fooM: FooMethod;
declare type FooAsyncMethod = {
method(...args: [
type: "str",
cb: (e: string) => void
] | [
type: "num",
cb: (e: number) => void
]): Promise<any>;
};
declare let fooAsyncM: FooAsyncMethod;
declare type FooGenMethod = {
method(...args: [
type: "str",
cb: (e: string) => void
] | [
type: "num",
cb: (e: number) => void
]): Generator<any, any, any>;
};
declare let fooGenM: FooGenMethod;
declare type FooAsyncGenMethod = {
method(...args: [
type: "str",
cb: (e: string) => void
] | [
type: "num",
cb: (e: number) => void
]): AsyncGenerator<any, any, any>;
};
declare let fooAsyncGenM: FooAsyncGenMethod;

View File

@@ -321,7 +321,7 @@ interface B<T> { variant: 'b', value: Array<T> }
>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 128, 12))
>variant : Symbol(B.variant, Decl(dependentDestructuredVariables.ts, 128, 16))
>value : Symbol(B.value, Decl(dependentDestructuredVariables.ts, 128, 30))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)
>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 128, 12))
type AB<T> = A<T> | B<T>;
@@ -342,7 +342,7 @@ declare function printValueList<T>(t: Array<T>): void;
>printValueList : Symbol(printValueList, Decl(dependentDestructuredVariables.ts, 132, 43))
>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 134, 32))
>t : Symbol(t, Decl(dependentDestructuredVariables.ts, 134, 35))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more)
>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 134, 32))
function unrefined1<T>(ab: AB<T>): void {
@@ -514,7 +514,7 @@ declare function readFile(path: string, callback: (...args: [err: null, data: un
>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, --, --))
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --))
readFile('hello', (err, data) => {
>readFile : Symbol(readFile, Decl(dependentDestructuredVariables.ts, 198, 2))
@@ -595,3 +595,160 @@ reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });
>firstArr : Symbol(firstArr, Decl(dependentDestructuredVariables.ts, 225, 19))
>secondArr : Symbol(secondArr, Decl(dependentDestructuredVariables.ts, 225, 37))
// repro from https://github.com/microsoft/TypeScript/pull/47190#issuecomment-1057603588
type FooMethod = {
>FooMethod : Symbol(FooMethod, Decl(dependentDestructuredVariables.ts, 225, 59))
method(...args:
>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 229, 18))
>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 230, 9))
[type: "str", cb: (e: string) => void] |
>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 231, 23))
[type: "num", cb: (e: number) => void]
>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 232, 23))
): void;
}
let fooM: FooMethod = {
>fooM : Symbol(fooM, Decl(dependentDestructuredVariables.ts, 236, 3))
>FooMethod : Symbol(FooMethod, Decl(dependentDestructuredVariables.ts, 225, 59))
method(type, cb) {
>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 236, 23))
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 237, 9))
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 237, 14))
if (type == 'num') {
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 237, 9))
cb(123)
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 237, 14))
} else {
cb("abc")
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 237, 14))
}
}
};
type FooAsyncMethod = {
>FooAsyncMethod : Symbol(FooAsyncMethod, Decl(dependentDestructuredVariables.ts, 244, 2))
method(...args:
>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 246, 23))
>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 247, 9))
[type: "str", cb: (e: string) => void] |
>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 248, 23))
[type: "num", cb: (e: number) => void]
>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 249, 23))
): Promise<any>;
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
}
let fooAsyncM: FooAsyncMethod = {
>fooAsyncM : Symbol(fooAsyncM, Decl(dependentDestructuredVariables.ts, 253, 3))
>FooAsyncMethod : Symbol(FooAsyncMethod, Decl(dependentDestructuredVariables.ts, 244, 2))
async method(type, cb) {
>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 253, 33))
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 254, 15))
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 254, 20))
if (type == 'num') {
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 254, 15))
cb(123)
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 254, 20))
} else {
cb("abc")
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 254, 20))
}
}
};
type FooGenMethod = {
>FooGenMethod : Symbol(FooGenMethod, Decl(dependentDestructuredVariables.ts, 261, 2))
method(...args:
>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 263, 21))
>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 264, 9))
[type: "str", cb: (e: string) => void] |
>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 265, 23))
[type: "num", cb: (e: number) => void]
>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 266, 23))
): Generator<any, any, any>;
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
}
let fooGenM: FooGenMethod = {
>fooGenM : Symbol(fooGenM, Decl(dependentDestructuredVariables.ts, 270, 3))
>FooGenMethod : Symbol(FooGenMethod, Decl(dependentDestructuredVariables.ts, 261, 2))
*method(type, cb) {
>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 270, 29))
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 271, 10))
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 271, 15))
if (type == 'num') {
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 271, 10))
cb(123)
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 271, 15))
} else {
cb("abc")
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 271, 15))
}
}
};
type FooAsyncGenMethod = {
>FooAsyncGenMethod : Symbol(FooAsyncGenMethod, Decl(dependentDestructuredVariables.ts, 278, 2))
method(...args:
>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 280, 26))
>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 281, 9))
[type: "str", cb: (e: string) => void] |
>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 282, 23))
[type: "num", cb: (e: number) => void]
>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 283, 23))
): AsyncGenerator<any, any, any>;
>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --))
}
let fooAsyncGenM: FooAsyncGenMethod = {
>fooAsyncGenM : Symbol(fooAsyncGenM, Decl(dependentDestructuredVariables.ts, 287, 3))
>FooAsyncGenMethod : Symbol(FooAsyncGenMethod, Decl(dependentDestructuredVariables.ts, 278, 2))
async *method(type, cb) {
>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 287, 39))
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 288, 16))
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 288, 21))
if (type == 'num') {
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 288, 16))
cb(123)
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 288, 21))
} else {
cb("abc")
>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 288, 21))
}
}
};

View File

@@ -677,3 +677,181 @@ reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });
>3 : 3
>4 : 4
// repro from https://github.com/microsoft/TypeScript/pull/47190#issuecomment-1057603588
type FooMethod = {
>FooMethod : FooMethod
method(...args:
>method : (...args: [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]) => void
>args : [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]
[type: "str", cb: (e: string) => void] |
>e : string
[type: "num", cb: (e: number) => void]
>e : number
): void;
}
let fooM: FooMethod = {
>fooM : FooMethod
>{ method(type, cb) { if (type == 'num') { cb(123) } else { cb("abc") } }} : { method(type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)): void; }
method(type, cb) {
>method : (type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)) => void
>type : "str" | "num"
>cb : ((e: string) => void) | ((e: number) => void)
if (type == 'num') {
>type == 'num' : boolean
>type : "str" | "num"
>'num' : "num"
cb(123)
>cb(123) : void
>cb : (e: number) => void
>123 : 123
} else {
cb("abc")
>cb("abc") : void
>cb : (e: string) => void
>"abc" : "abc"
}
}
};
type FooAsyncMethod = {
>FooAsyncMethod : FooAsyncMethod
method(...args:
>method : (...args: [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]) => Promise<any>
>args : [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]
[type: "str", cb: (e: string) => void] |
>e : string
[type: "num", cb: (e: number) => void]
>e : number
): Promise<any>;
}
let fooAsyncM: FooAsyncMethod = {
>fooAsyncM : FooAsyncMethod
>{ async method(type, cb) { if (type == 'num') { cb(123) } else { cb("abc") } }} : { method(type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)): Promise<void>; }
async method(type, cb) {
>method : (type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)) => Promise<void>
>type : "str" | "num"
>cb : ((e: string) => void) | ((e: number) => void)
if (type == 'num') {
>type == 'num' : boolean
>type : "str" | "num"
>'num' : "num"
cb(123)
>cb(123) : void
>cb : (e: number) => void
>123 : 123
} else {
cb("abc")
>cb("abc") : void
>cb : (e: string) => void
>"abc" : "abc"
}
}
};
type FooGenMethod = {
>FooGenMethod : FooGenMethod
method(...args:
>method : (...args: [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]) => Generator<any, any, any>
>args : [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]
[type: "str", cb: (e: string) => void] |
>e : string
[type: "num", cb: (e: number) => void]
>e : number
): Generator<any, any, any>;
}
let fooGenM: FooGenMethod = {
>fooGenM : FooGenMethod
>{ *method(type, cb) { if (type == 'num') { cb(123) } else { cb("abc") } }} : { method(type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)): Generator<never, void, any>; }
*method(type, cb) {
>method : (type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)) => Generator<never, void, any>
>type : "str" | "num"
>cb : ((e: string) => void) | ((e: number) => void)
if (type == 'num') {
>type == 'num' : boolean
>type : "str" | "num"
>'num' : "num"
cb(123)
>cb(123) : void
>cb : (e: number) => void
>123 : 123
} else {
cb("abc")
>cb("abc") : void
>cb : (e: string) => void
>"abc" : "abc"
}
}
};
type FooAsyncGenMethod = {
>FooAsyncGenMethod : FooAsyncGenMethod
method(...args:
>method : (...args: [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]) => AsyncGenerator<any, any, any>
>args : [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]
[type: "str", cb: (e: string) => void] |
>e : string
[type: "num", cb: (e: number) => void]
>e : number
): AsyncGenerator<any, any, any>;
}
let fooAsyncGenM: FooAsyncGenMethod = {
>fooAsyncGenM : FooAsyncGenMethod
>{ async *method(type, cb) { if (type == 'num') { cb(123) } else { cb("abc") } }} : { method(type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)): AsyncGenerator<never, void, any>; }
async *method(type, cb) {
>method : (type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)) => AsyncGenerator<never, void, any>
>type : "str" | "num"
>cb : ((e: string) => void) | ((e: number) => void)
if (type == 'num') {
>type == 'num' : boolean
>type : "str" | "num"
>'num' : "num"
cb(123)
>cb(123) : void
>cb : (e: number) => void
>123 : 123
} else {
cb("abc")
>cb("abc") : void
>cb : (e: string) => void
>"abc" : "abc"
}
}
};

View File

@@ -1,6 +1,7 @@
// @strict: true
// @declaration: true
// @target: es2015
// @lib: esnext, dom
type Action =
| { kind: 'A', payload: number }
@@ -228,3 +229,73 @@ const reducer: (...args: ReducerArgs) => void = (op, args) => {
reducer("add", { a: 1, b: 3 });
reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });
// repro from https://github.com/microsoft/TypeScript/pull/47190#issuecomment-1057603588
type FooMethod = {
method(...args:
[type: "str", cb: (e: string) => void] |
[type: "num", cb: (e: number) => void]
): void;
}
let fooM: FooMethod = {
method(type, cb) {
if (type == 'num') {
cb(123)
} else {
cb("abc")
}
}
};
type FooAsyncMethod = {
method(...args:
[type: "str", cb: (e: string) => void] |
[type: "num", cb: (e: number) => void]
): Promise<any>;
}
let fooAsyncM: FooAsyncMethod = {
async method(type, cb) {
if (type == 'num') {
cb(123)
} else {
cb("abc")
}
}
};
type FooGenMethod = {
method(...args:
[type: "str", cb: (e: string) => void] |
[type: "num", cb: (e: number) => void]
): Generator<any, any, any>;
}
let fooGenM: FooGenMethod = {
*method(type, cb) {
if (type == 'num') {
cb(123)
} else {
cb("abc")
}
}
};
type FooAsyncGenMethod = {
method(...args:
[type: "str", cb: (e: string) => void] |
[type: "num", cb: (e: number) => void]
): AsyncGenerator<any, any, any>;
}
let fooAsyncGenM: FooAsyncGenMethod = {
async *method(type, cb) {
if (type == 'num') {
cb(123)
} else {
cb("abc")
}
}
};