From 05442d085f2c2f3142f3cea89ea870558f423782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 17 Oct 2022 10:21:33 +0200 Subject: [PATCH 1/7] Filter possible contextual return types from unions for async functions and generators --- src/compiler/checker.ts | 39 +++++-- ...peAsyncFunctionReturnTypeFromUnion.symbols | 100 +++++++++++++++++ ...TypeAsyncFunctionReturnTypeFromUnion.types | 106 ++++++++++++++++++ ...lyTypeGeneratorReturnTypeFromUnion.symbols | 36 ++++++ ...allyTypeGeneratorReturnTypeFromUnion.types | 44 ++++++++ ...llyTypeAsyncFunctionReturnTypeFromUnion.ts | 37 ++++++ ...xtuallyTypeGeneratorReturnTypeFromUnion.ts | 19 ++++ 7 files changed, 369 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.symbols create mode 100644 tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.types create mode 100644 tests/baselines/reference/contextuallyTypeGeneratorReturnTypeFromUnion.symbols create mode 100644 tests/baselines/reference/contextuallyTypeGeneratorReturnTypeFromUnion.types create mode 100644 tests/cases/compiler/contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts create mode 100644 tests/cases/compiler/contextuallyTypeGeneratorReturnTypeFromUnion.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d439ec7db6350..98f3af2a0c0be 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27181,7 +27181,17 @@ namespace ts { // and that call signature is non-generic, return statements are contextually typed by the return type of the signature const signature = getContextualSignatureForFunctionLikeDeclaration(functionDecl as FunctionExpression); if (signature && !isResolvingReturnTypeOfSignature(signature)) { - return getReturnTypeOfSignature(signature); + const functionFlags = getFunctionFlags(functionDecl); + + return filterType(getReturnTypeOfSignature(signature), returnType => { + if (functionFlags & FunctionFlags.Generator) { + return checkGeneratorInstantiationAssignabilityToReturnType(returnType, functionFlags, /*errorNode*/ undefined); + } + if (functionFlags & FunctionFlags.Async) { + return !!getAwaitedTypeOfPromise(returnType); + } + return true; + }); } const iife = getImmediatelyInvokedFunctionExpression(functionDecl); if (iife) { @@ -35804,17 +35814,7 @@ namespace ts { error(returnTypeNode, Diagnostics.A_generator_cannot_have_a_void_type_annotation); } else { - // Naively, one could check that Generator is assignable to the return type annotation. - // However, that would not catch the error in the following case. - // - // interface BadGenerator extends Iterable, Iterator { } - // function* g(): BadGenerator { } // Iterable and Iterator have different types! - // - const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, returnType, (functionFlags & FunctionFlags.Async) !== 0) || anyType; - const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, (functionFlags & FunctionFlags.Async) !== 0) || generatorYieldType; - const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, (functionFlags & FunctionFlags.Async) !== 0) || unknownType; - const generatorInstantiation = createGeneratorReturnType(generatorYieldType, generatorReturnType, generatorNextType, !!(functionFlags & FunctionFlags.Async)); - checkTypeAssignableTo(generatorInstantiation, returnType, returnTypeNode); + checkGeneratorInstantiationAssignabilityToReturnType(returnType, functionFlags, returnTypeNode); } } else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { @@ -35827,6 +35827,21 @@ namespace ts { } } + function checkGeneratorInstantiationAssignabilityToReturnType(returnType: Type, functionFlags: FunctionFlags, errorNode?: TypeNode) { + // Naively, one could check that Generator is assignable to the return type annotation. + // However, that would not catch the error in the following case. + // + // interface BadGenerator extends Iterable, Iterator { } + // function* g(): BadGenerator { } // Iterable and Iterator have different types! + // + const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, returnType, (functionFlags & FunctionFlags.Async) !== 0) || anyType; + const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, (functionFlags & FunctionFlags.Async) !== 0) || generatorYieldType; + const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, (functionFlags & FunctionFlags.Async) !== 0) || unknownType; + const generatorInstantiation = createGeneratorReturnType(generatorYieldType, generatorReturnType, generatorNextType, !!(functionFlags & FunctionFlags.Async)); + + return checkTypeAssignableTo(generatorInstantiation, returnType, errorNode); + } + function checkClassForDuplicateDeclarations(node: ClassLikeDeclaration) { const instanceNames = new Map<__String, DeclarationMeaning>(); const staticNames = new Map<__String, DeclarationMeaning>(); diff --git a/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.symbols b/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.symbols new file mode 100644 index 0000000000000..62c0b5374aa5e --- /dev/null +++ b/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.symbols @@ -0,0 +1,100 @@ +=== tests/cases/compiler/contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts === +// repro #47682 + +declare class StateMachine { +>StateMachine : Symbol(StateMachine, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 0, 0)) +>T : Symbol(T, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 2, 27)) + + onDone: (a: T) => void; +>onDone : Symbol(StateMachine.onDone, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 2, 31)) +>a : Symbol(a, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 3, 11)) +>T : Symbol(T, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 2, 27)) +} + +declare function createMachine(implementations: { +>createMachine : Symbol(createMachine, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 4, 1)) +>T : Symbol(T, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 6, 31)) +>implementations : Symbol(implementations, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 6, 34)) + + services: Record Promise | StateMachine>; +>services : Symbol(services, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 6, 52)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>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, --, --)) +>T : Symbol(T, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 6, 31)) +>StateMachine : Symbol(StateMachine, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 0, 0)) +>T : Symbol(T, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 6, 31)) + +}): void; + +createMachine<{ count: number }>({ +>createMachine : Symbol(createMachine, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 4, 1)) +>count : Symbol(count, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 10, 15)) + + services: { +>services : Symbol(services, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 10, 34)) + + test: async () => Promise.reject("some err"), +>test : Symbol(test, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 11, 13)) +>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --)) +>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, --, --)) +>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --)) + + async test2() { +>test2 : Symbol(test2, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 12, 49)) + + return Promise.reject("some err"); +>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --)) +>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, --, --)) +>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --)) + + }, + }, +}); + +function fn1(): () => Promise<{ count: number }> | StateMachine<{ count: number }> { +>fn1 : Symbol(fn1, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 17, 3)) +>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, --, --)) +>count : Symbol(count, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 19, 31)) +>StateMachine : Symbol(StateMachine, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 0, 0)) +>count : Symbol(count, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 19, 65)) + + return async () => Promise.reject('some err') +>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --)) +>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, --, --)) +>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --)) +} + +// repro #47682 issuecomment-1174099713 + +declare function load(): Promise; +>load : Symbol(load, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 21, 1)) +>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, --, --)) + +type LoadCallback = () => Promise | string; +>LoadCallback : Symbol(LoadCallback, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 25, 42)) +>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, --, --)) + +// all of those are essentially the same and should be allowed +const cb1: LoadCallback = async () => load().then(m => m); +>cb1 : Symbol(cb1, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 30, 5)) +>LoadCallback : Symbol(LoadCallback, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 25, 42)) +>load().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>load : Symbol(load, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 21, 1)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>m : Symbol(m, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 30, 50)) +>m : Symbol(m, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 30, 50)) + +const cb2: LoadCallback = async () => load(); +>cb2 : Symbol(cb2, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 31, 5)) +>LoadCallback : Symbol(LoadCallback, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 25, 42)) +>load : Symbol(load, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 21, 1)) + +const cb3: LoadCallback = () => load().then(m => m); +>cb3 : Symbol(cb3, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 32, 5)) +>LoadCallback : Symbol(LoadCallback, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 25, 42)) +>load().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>load : Symbol(load, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 21, 1)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>m : Symbol(m, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 32, 44)) +>m : Symbol(m, Decl(contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts, 32, 44)) + diff --git a/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.types b/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.types new file mode 100644 index 0000000000000..ed69900929264 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.types @@ -0,0 +1,106 @@ +=== tests/cases/compiler/contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts === +// repro #47682 + +declare class StateMachine { +>StateMachine : StateMachine + + onDone: (a: T) => void; +>onDone : (a: T) => void +>a : T +} + +declare function createMachine(implementations: { +>createMachine : (implementations: { services: Record Promise | StateMachine>;}) => void +>implementations : { services: Record Promise | StateMachine>; } + + services: Record Promise | StateMachine>; +>services : Record Promise | StateMachine> + +}): void; + +createMachine<{ count: number }>({ +>createMachine<{ count: number }>({ services: { test: async () => Promise.reject("some err"), async test2() { return Promise.reject("some err"); }, },}) : void +>createMachine : (implementations: { services: Record Promise | StateMachine>; }) => void +>count : number +>{ services: { test: async () => Promise.reject("some err"), async test2() { return Promise.reject("some err"); }, },} : { services: { test: () => Promise<{ count: number; }>; test2(): Promise<{ count: number; }>; }; } + + services: { +>services : { test: () => Promise<{ count: number; }>; test2(): Promise<{ count: number; }>; } +>{ test: async () => Promise.reject("some err"), async test2() { return Promise.reject("some err"); }, } : { test: () => Promise<{ count: number; }>; test2(): Promise<{ count: number; }>; } + + test: async () => Promise.reject("some err"), +>test : () => Promise<{ count: number; }> +>async () => Promise.reject("some err") : () => Promise<{ count: number; }> +>Promise.reject("some err") : Promise<{ count: number; }> +>Promise.reject : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise +>"some err" : "some err" + + async test2() { +>test2 : () => Promise<{ count: number; }> + + return Promise.reject("some err"); +>Promise.reject("some err") : Promise<{ count: number; }> +>Promise.reject : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise +>"some err" : "some err" + + }, + }, +}); + +function fn1(): () => Promise<{ count: number }> | StateMachine<{ count: number }> { +>fn1 : () => () => Promise<{ count: number;}> | StateMachine<{ count: number;}> +>count : number +>count : number + + return async () => Promise.reject('some err') +>async () => Promise.reject('some err') : () => Promise<{ count: number; }> +>Promise.reject('some err') : Promise<{ count: number; }> +>Promise.reject : (reason?: any) => Promise +>Promise : PromiseConstructor +>reject : (reason?: any) => Promise +>'some err' : "some err" +} + +// repro #47682 issuecomment-1174099713 + +declare function load(): Promise; +>load : () => Promise + +type LoadCallback = () => Promise | string; +>LoadCallback : () => Promise | string + +// all of those are essentially the same and should be allowed +const cb1: LoadCallback = async () => load().then(m => m); +>cb1 : LoadCallback +>async () => load().then(m => m) : () => Promise +>load().then(m => m) : Promise +>load().then : (onfulfilled?: ((value: boolean) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>load() : Promise +>load : () => Promise +>then : (onfulfilled?: ((value: boolean) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>m => m : (m: boolean) => boolean +>m : boolean +>m : boolean + +const cb2: LoadCallback = async () => load(); +>cb2 : LoadCallback +>async () => load() : () => Promise +>load() : Promise +>load : () => Promise + +const cb3: LoadCallback = () => load().then(m => m); +>cb3 : LoadCallback +>() => load().then(m => m) : () => Promise +>load().then(m => m) : Promise +>load().then : (onfulfilled?: ((value: boolean) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>load() : Promise +>load : () => Promise +>then : (onfulfilled?: ((value: boolean) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>m => m : (m: boolean) => boolean +>m : boolean +>m : boolean + diff --git a/tests/baselines/reference/contextuallyTypeGeneratorReturnTypeFromUnion.symbols b/tests/baselines/reference/contextuallyTypeGeneratorReturnTypeFromUnion.symbols new file mode 100644 index 0000000000000..0d89756b21226 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypeGeneratorReturnTypeFromUnion.symbols @@ -0,0 +1,36 @@ +=== tests/cases/compiler/contextuallyTypeGeneratorReturnTypeFromUnion.ts === +// repro #51187 + +type Action = () => (Generator | string) +>Action : Symbol(Action, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 0, 0)) +>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) + +const test1: Action = function* () { +>test1 : Symbol(test1, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 4, 5)) +>Action : Symbol(Action, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 0, 0)) + + const next = yield '' +>next : Symbol(next, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 5, 9)) + + return next[0] +>next : Symbol(next, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 5, 9)) +} + +type Action2 = () => (AsyncGenerator | string) +>Action2 : Symbol(Action2, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 7, 1)) +>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --)) + +const test2: Action2 = async function* () { +>test2 : Symbol(test2, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 11, 5)) +>Action2 : Symbol(Action2, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 7, 1)) + + const next = yield await Promise.resolve('') +>next : Symbol(next, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 12, 9)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>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, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) + + return next[0] +>next : Symbol(next, Decl(contextuallyTypeGeneratorReturnTypeFromUnion.ts, 12, 9)) +} + diff --git a/tests/baselines/reference/contextuallyTypeGeneratorReturnTypeFromUnion.types b/tests/baselines/reference/contextuallyTypeGeneratorReturnTypeFromUnion.types new file mode 100644 index 0000000000000..150a035eb4bbb --- /dev/null +++ b/tests/baselines/reference/contextuallyTypeGeneratorReturnTypeFromUnion.types @@ -0,0 +1,44 @@ +=== tests/cases/compiler/contextuallyTypeGeneratorReturnTypeFromUnion.ts === +// repro #51187 + +type Action = () => (Generator | string) +>Action : () => (Generator | string) + +const test1: Action = function* () { +>test1 : Action +>function* () { const next = yield '' return next[0]} : () => Generator + + const next = yield '' +>next : string[] +>yield '' : string[] +>'' : "" + + return next[0] +>next[0] : string +>next : string[] +>0 : 0 +} + +type Action2 = () => (AsyncGenerator | string) +>Action2 : () => (AsyncGenerator | string) + +const test2: Action2 = async function* () { +>test2 : Action2 +>async function* () { const next = yield await Promise.resolve('') return next[0]} : () => AsyncGenerator + + const next = yield await Promise.resolve('') +>next : string[] +>yield await Promise.resolve('') : string[] +>await Promise.resolve('') : string +>Promise.resolve('') : Promise +>Promise.resolve : { (): Promise; (value: T): Promise>; (value: T | PromiseLike): Promise>; } +>Promise : PromiseConstructor +>resolve : { (): Promise; (value: T): Promise>; (value: T | PromiseLike): Promise>; } +>'' : "" + + return next[0] +>next[0] : string +>next : string[] +>0 : 0 +} + diff --git a/tests/cases/compiler/contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts b/tests/cases/compiler/contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts new file mode 100644 index 0000000000000..16236ae43ec1b --- /dev/null +++ b/tests/cases/compiler/contextuallyTypeAsyncFunctionReturnTypeFromUnion.ts @@ -0,0 +1,37 @@ +// @strict: true +// @noEmit: true +// @target: esnext + +// repro #47682 + +declare class StateMachine { + onDone: (a: T) => void; +} + +declare function createMachine(implementations: { + services: Record Promise | StateMachine>; +}): void; + +createMachine<{ count: number }>({ + services: { + test: async () => Promise.reject("some err"), + async test2() { + return Promise.reject("some err"); + }, + }, +}); + +function fn1(): () => Promise<{ count: number }> | StateMachine<{ count: number }> { + return async () => Promise.reject('some err') +} + +// repro #47682 issuecomment-1174099713 + +declare function load(): Promise; + +type LoadCallback = () => Promise | string; + +// all of those are essentially the same and should be allowed +const cb1: LoadCallback = async () => load().then(m => m); +const cb2: LoadCallback = async () => load(); +const cb3: LoadCallback = () => load().then(m => m); \ No newline at end of file diff --git a/tests/cases/compiler/contextuallyTypeGeneratorReturnTypeFromUnion.ts b/tests/cases/compiler/contextuallyTypeGeneratorReturnTypeFromUnion.ts new file mode 100644 index 0000000000000..23a9d70bcac3f --- /dev/null +++ b/tests/cases/compiler/contextuallyTypeGeneratorReturnTypeFromUnion.ts @@ -0,0 +1,19 @@ +// @strict: true +// @noEmit: true +// @lib: esnext + +// repro #51187 + +type Action = () => (Generator | string) + +const test1: Action = function* () { + const next = yield '' + return next[0] +} + +type Action2 = () => (AsyncGenerator | string) + +const test2: Action2 = async function* () { + const next = yield await Promise.resolve('') + return next[0] +} From 1d98fe09bfc59c01305d2028b49e0f4752a7e432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 17 Oct 2022 11:06:40 +0200 Subject: [PATCH 2/7] accept new baselines --- tests/baselines/reference/contextualTypeOnYield1.types | 4 ++-- tests/baselines/reference/contextualTypeOnYield2.types | 2 +- .../baselines/reference/generatorYieldContextualType.types | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/contextualTypeOnYield1.types b/tests/baselines/reference/contextualTypeOnYield1.types index 60cac2c6c1c70..3eba46f542162 100644 --- a/tests/baselines/reference/contextualTypeOnYield1.types +++ b/tests/baselines/reference/contextualTypeOnYield1.types @@ -5,10 +5,10 @@ type FuncOrGeneratorFunc = () => (number | Generator<(arg: number) => void, any, const f: FuncOrGeneratorFunc = function*() { >f : FuncOrGeneratorFunc ->function*() { yield (num) => console.log(num); // `num` should be inferred to have type `number`.} : () => Generator<(num: number) => void, void, unknown> +>function*() { yield (num) => console.log(num); // `num` should be inferred to have type `number`.} : () => Generator<(num: number) => void, void, void> yield (num) => console.log(num); // `num` should be inferred to have type `number`. ->yield (num) => console.log(num) : any +>yield (num) => console.log(num) : void >(num) => console.log(num) : (num: number) => void >num : number >console.log(num) : void diff --git a/tests/baselines/reference/contextualTypeOnYield2.types b/tests/baselines/reference/contextualTypeOnYield2.types index 0ae99969ac760..683ff3a483c2f 100644 --- a/tests/baselines/reference/contextualTypeOnYield2.types +++ b/tests/baselines/reference/contextualTypeOnYield2.types @@ -5,7 +5,7 @@ type OrGen = () => (number | Generator void, undefined> const g: OrGen = function* () { >g : OrGen ->function* () { return (num) => console.log(num);} : () => Generator void, unknown> +>function* () { return (num) => console.log(num);} : () => Generator void, undefined> return (num) => console.log(num); >(num) => console.log(num) : (num: number) => void diff --git a/tests/baselines/reference/generatorYieldContextualType.types b/tests/baselines/reference/generatorYieldContextualType.types index 13a2b85267d14..a90bbd040a1cb 100644 --- a/tests/baselines/reference/generatorYieldContextualType.types +++ b/tests/baselines/reference/generatorYieldContextualType.types @@ -25,11 +25,11 @@ declare function f2(gen: () => Generator | AsyncGenerator(async function* () { >f2<0, 0, 1>(async function* () { const a = yield 0; return 0;}) : void >f2 : (gen: () => Generator | AsyncGenerator) => void ->async function* () { const a = yield 0; return 0;} : () => AsyncGenerator<0, 0, 1 | undefined> +>async function* () { const a = yield 0; return 0;} : () => AsyncGenerator<0, 0, 1> const a = yield 0; ->a : 1 | undefined ->yield 0 : 1 | undefined +>a : 1 +>yield 0 : 1 >0 : 0 return 0; From dfe955a861eec22029dc12bd5fc2f0db881ede12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 5 Mar 2023 11:10:24 +0100 Subject: [PATCH 3/7] Filter annotated return type within `checkYieldExpression` --- src/compiler/checker.ts | 5 +- .../generatorYieldContextualType.symbols | 319 ++++++++++++++++++ .../generatorYieldContextualType.types | 237 +++++++++++++ .../generatorYieldContextualType.ts | 107 +++++- 4 files changed, 666 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2cc014ca0d348..6acb18a718d1d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -36967,7 +36967,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // There is no point in doing an assignability check if the function // has no explicit return type because the return type is directly computed // from the yield expressions. - const returnType = getReturnTypeFromAnnotation(func); + let returnType = getReturnTypeFromAnnotation(func); + if (returnType && returnType.flags & TypeFlags.Union) { + returnType = filterType(returnType, t => checkGeneratorInstantiationAssignabilityToReturnType(t, functionFlags, /*errorNode*/ undefined)); + } const iterationTypes = returnType && getIterationTypesOfGeneratorFunctionReturnType(returnType, isAsync); const signatureYieldType = iterationTypes && iterationTypes.yieldType || anyType; const signatureNextType = iterationTypes && iterationTypes.nextType || anyType; diff --git a/tests/baselines/reference/generatorYieldContextualType.symbols b/tests/baselines/reference/generatorYieldContextualType.symbols index 80d20b90d752e..535bba7c03e5a 100644 --- a/tests/baselines/reference/generatorYieldContextualType.symbols +++ b/tests/baselines/reference/generatorYieldContextualType.symbols @@ -42,3 +42,322 @@ f2<0, 0, 1>(async function* () { return 0; }); + +// repro from #41428 +enum Directive { +>Directive : Symbol(Directive, Decl(generatorYieldContextualType.ts, 10, 3), Decl(generatorYieldContextualType.ts, 18, 1)) + + Back, +>Back : Symbol(Directive.Back, Decl(generatorYieldContextualType.ts, 13, 16)) + + Cancel, +>Cancel : Symbol(Directive.Cancel, Decl(generatorYieldContextualType.ts, 14, 7)) + + LoadMore, +>LoadMore : Symbol(Directive.LoadMore, Decl(generatorYieldContextualType.ts, 15, 9)) + + Noop, +>Noop : Symbol(Directive.Noop, Decl(generatorYieldContextualType.ts, 16, 11)) +} + +namespace Directive { +>Directive : Symbol(Directive, Decl(generatorYieldContextualType.ts, 10, 3), Decl(generatorYieldContextualType.ts, 18, 1)) + + export function is(value: Directive | T): value is Directive { +>is : Symbol(is, Decl(generatorYieldContextualType.ts, 20, 21)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 21, 21)) +>value : Symbol(value, Decl(generatorYieldContextualType.ts, 21, 24)) +>Directive : Symbol(Directive, Decl(generatorYieldContextualType.ts, 10, 3), Decl(generatorYieldContextualType.ts, 18, 1)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 21, 21)) +>value : Symbol(value, Decl(generatorYieldContextualType.ts, 21, 24)) +>Directive : Symbol(Directive, Decl(generatorYieldContextualType.ts, 10, 3), Decl(generatorYieldContextualType.ts, 18, 1)) + + return typeof value === "number" && Directive[value] != null; +>value : Symbol(value, Decl(generatorYieldContextualType.ts, 21, 24)) +>Directive : Symbol(Directive, Decl(generatorYieldContextualType.ts, 10, 3), Decl(generatorYieldContextualType.ts, 18, 1)) +>value : Symbol(value, Decl(generatorYieldContextualType.ts, 21, 24)) + } +} + +interface QuickPickItem { +>QuickPickItem : Symbol(QuickPickItem, Decl(generatorYieldContextualType.ts, 24, 1)) + + label: string; +>label : Symbol(QuickPickItem.label, Decl(generatorYieldContextualType.ts, 26, 25)) + + description?: string; +>description : Symbol(QuickPickItem.description, Decl(generatorYieldContextualType.ts, 27, 16)) + + detail?: string; +>detail : Symbol(QuickPickItem.detail, Decl(generatorYieldContextualType.ts, 28, 23)) + + picked?: boolean; +>picked : Symbol(QuickPickItem.picked, Decl(generatorYieldContextualType.ts, 29, 18)) + + alwaysShow?: boolean; +>alwaysShow : Symbol(QuickPickItem.alwaysShow, Decl(generatorYieldContextualType.ts, 30, 19)) +} + +interface QuickInputStep { +>QuickInputStep : Symbol(QuickInputStep, Decl(generatorYieldContextualType.ts, 32, 1)) + + placeholder?: string; +>placeholder : Symbol(QuickInputStep.placeholder, Decl(generatorYieldContextualType.ts, 34, 26)) + + prompt?: string; +>prompt : Symbol(QuickInputStep.prompt, Decl(generatorYieldContextualType.ts, 35, 23)) + + title?: string; +>title : Symbol(QuickInputStep.title, Decl(generatorYieldContextualType.ts, 36, 18)) +} + +interface QuickPickStep { +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 40, 24)) +>QuickPickItem : Symbol(QuickPickItem, Decl(generatorYieldContextualType.ts, 24, 1)) +>QuickPickItem : Symbol(QuickPickItem, Decl(generatorYieldContextualType.ts, 24, 1)) + + placeholder?: string; +>placeholder : Symbol(QuickPickStep.placeholder, Decl(generatorYieldContextualType.ts, 40, 66)) + + title?: string; +>title : Symbol(QuickPickStep.title, Decl(generatorYieldContextualType.ts, 41, 23)) +} + +type StepGenerator = +>StepGenerator : Symbol(StepGenerator, Decl(generatorYieldContextualType.ts, 43, 1)) + + | Generator< +>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) + + QuickPickStep | QuickInputStep, +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>QuickInputStep : Symbol(QuickInputStep, Decl(generatorYieldContextualType.ts, 32, 1)) + + StepResult, +>StepResult : Symbol(StepResult, Decl(generatorYieldContextualType.ts, 61, 10), Decl(generatorYieldContextualType.ts, 64, 1)) + + any | undefined + > + | AsyncGenerator< +>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --)) + + QuickPickStep | QuickInputStep, +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>QuickInputStep : Symbol(QuickInputStep, Decl(generatorYieldContextualType.ts, 32, 1)) + + StepResult, +>StepResult : Symbol(StepResult, Decl(generatorYieldContextualType.ts, 61, 10), Decl(generatorYieldContextualType.ts, 64, 1)) + + any | undefined + >; + +type StepItemType = T extends QuickPickStep +>StepItemType : Symbol(StepItemType, Decl(generatorYieldContextualType.ts, 55, 6)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 57, 18)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 57, 18)) +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>U : Symbol(U, Decl(generatorYieldContextualType.ts, 57, 52)) + + ? U[] +>U : Symbol(U, Decl(generatorYieldContextualType.ts, 57, 52)) + + : T extends QuickInputStep +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 57, 18)) +>QuickInputStep : Symbol(QuickInputStep, Decl(generatorYieldContextualType.ts, 32, 1)) + + ? string + : never; +namespace StepResult { +>StepResult : Symbol(StepResult, Decl(generatorYieldContextualType.ts, 61, 10), Decl(generatorYieldContextualType.ts, 64, 1)) + + export const Break = Symbol("BreakStep"); +>Break : Symbol(Break, Decl(generatorYieldContextualType.ts, 63, 14)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +} +type StepResult = typeof StepResult.Break | T; +>StepResult : Symbol(StepResult, Decl(generatorYieldContextualType.ts, 61, 10), Decl(generatorYieldContextualType.ts, 64, 1)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 65, 16)) +>StepResult.Break : Symbol(StepResult.Break, Decl(generatorYieldContextualType.ts, 63, 14)) +>StepResult : Symbol(StepResult, Decl(generatorYieldContextualType.ts, 61, 10), Decl(generatorYieldContextualType.ts, 64, 1)) +>Break : Symbol(StepResult.Break, Decl(generatorYieldContextualType.ts, 63, 14)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 65, 16)) + +type StepResultGenerator = +>StepResultGenerator : Symbol(StepResultGenerator, Decl(generatorYieldContextualType.ts, 65, 49)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 66, 25)) + + | Generator, any | undefined> +>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>QuickInputStep : Symbol(QuickInputStep, Decl(generatorYieldContextualType.ts, 32, 1)) +>StepResult : Symbol(StepResult, Decl(generatorYieldContextualType.ts, 61, 10), Decl(generatorYieldContextualType.ts, 64, 1)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 66, 25)) + + | AsyncGenerator< +>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --)) + + QuickPickStep | QuickInputStep, +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>QuickInputStep : Symbol(QuickInputStep, Decl(generatorYieldContextualType.ts, 32, 1)) + + StepResult, +>StepResult : Symbol(StepResult, Decl(generatorYieldContextualType.ts, 61, 10), Decl(generatorYieldContextualType.ts, 64, 1)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 66, 25)) + + any | undefined + >; +type StepSelection = T extends QuickPickStep +>StepSelection : Symbol(StepSelection, Decl(generatorYieldContextualType.ts, 72, 6)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 73, 19)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 73, 19)) +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>U : Symbol(U, Decl(generatorYieldContextualType.ts, 73, 53)) + + ? U[] | Directive +>U : Symbol(U, Decl(generatorYieldContextualType.ts, 73, 53)) +>Directive : Symbol(Directive, Decl(generatorYieldContextualType.ts, 10, 3), Decl(generatorYieldContextualType.ts, 18, 1)) + + : T extends QuickInputStep +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 73, 19)) +>QuickInputStep : Symbol(QuickInputStep, Decl(generatorYieldContextualType.ts, 32, 1)) + + ? string | Directive +>Directive : Symbol(Directive, Decl(generatorYieldContextualType.ts, 10, 3), Decl(generatorYieldContextualType.ts, 18, 1)) + + : never; +type PartialStepState = Partial & { +>PartialStepState : Symbol(PartialStepState, Decl(generatorYieldContextualType.ts, 77, 10)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 78, 22)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 78, 22)) + + counter: number; +>counter : Symbol(counter, Decl(generatorYieldContextualType.ts, 78, 51)) + + confirm?: boolean; +>confirm : Symbol(confirm, Decl(generatorYieldContextualType.ts, 79, 18)) + + startingStep?: number; +>startingStep : Symbol(startingStep, Decl(generatorYieldContextualType.ts, 80, 20)) + +}; +type StepState> = T & { +>StepState : Symbol(StepState, Decl(generatorYieldContextualType.ts, 82, 2)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 83, 15)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 83, 15)) + + counter: number; +>counter : Symbol(counter, Decl(generatorYieldContextualType.ts, 83, 51)) + + confirm?: boolean; +>confirm : Symbol(confirm, Decl(generatorYieldContextualType.ts, 84, 18)) + + startingStep?: number; +>startingStep : Symbol(startingStep, Decl(generatorYieldContextualType.ts, 85, 20)) + +}; + +function canPickStepContinue( +>canPickStepContinue : Symbol(canPickStepContinue, Decl(generatorYieldContextualType.ts, 87, 2)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 89, 29)) +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) + + _step: T, +>_step : Symbol(_step, Decl(generatorYieldContextualType.ts, 89, 54)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 89, 29)) + + _state: PartialStepState, +>_state : Symbol(_state, Decl(generatorYieldContextualType.ts, 90, 11)) +>PartialStepState : Symbol(PartialStepState, Decl(generatorYieldContextualType.ts, 77, 10)) + + _selection: StepItemType | Directive +>_selection : Symbol(_selection, Decl(generatorYieldContextualType.ts, 91, 27)) +>StepItemType : Symbol(StepItemType, Decl(generatorYieldContextualType.ts, 55, 6)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 89, 29)) +>Directive : Symbol(Directive, Decl(generatorYieldContextualType.ts, 10, 3), Decl(generatorYieldContextualType.ts, 18, 1)) + +): _selection is StepItemType { +>_selection : Symbol(_selection, Decl(generatorYieldContextualType.ts, 91, 27)) +>StepItemType : Symbol(StepItemType, Decl(generatorYieldContextualType.ts, 55, 6)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 89, 29)) + + return false; +} + +function createPickStep( +>createPickStep : Symbol(createPickStep, Decl(generatorYieldContextualType.ts, 95, 1)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 97, 24)) +>QuickPickItem : Symbol(QuickPickItem, Decl(generatorYieldContextualType.ts, 24, 1)) + + step: QuickPickStep +>step : Symbol(step, Decl(generatorYieldContextualType.ts, 97, 49)) +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 97, 24)) + +): QuickPickStep { +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>T : Symbol(T, Decl(generatorYieldContextualType.ts, 97, 24)) + + return step; +>step : Symbol(step, Decl(generatorYieldContextualType.ts, 97, 49)) +} + +function* showStep< +>showStep : Symbol(showStep, Decl(generatorYieldContextualType.ts, 101, 1)) + + State extends PartialStepState & { repo: any }, +>State : Symbol(State, Decl(generatorYieldContextualType.ts, 103, 19)) +>PartialStepState : Symbol(PartialStepState, Decl(generatorYieldContextualType.ts, 77, 10)) +>repo : Symbol(repo, Decl(generatorYieldContextualType.ts, 104, 36)) + + Context extends { repos: any[]; title: string; status: any } +>Context : Symbol(Context, Decl(generatorYieldContextualType.ts, 104, 49)) +>repos : Symbol(repos, Decl(generatorYieldContextualType.ts, 105, 19)) +>title : Symbol(title, Decl(generatorYieldContextualType.ts, 105, 33)) +>status : Symbol(status, Decl(generatorYieldContextualType.ts, 105, 48)) + +>(state: State, _context: Context): StepResultGenerator { +>state : Symbol(state, Decl(generatorYieldContextualType.ts, 106, 2)) +>State : Symbol(State, Decl(generatorYieldContextualType.ts, 103, 19)) +>_context : Symbol(_context, Decl(generatorYieldContextualType.ts, 106, 15)) +>Context : Symbol(Context, Decl(generatorYieldContextualType.ts, 104, 49)) +>StepResultGenerator : Symbol(StepResultGenerator, Decl(generatorYieldContextualType.ts, 65, 49)) +>QuickPickItem : Symbol(QuickPickItem, Decl(generatorYieldContextualType.ts, 24, 1)) + + const step: QuickPickStep = createPickStep({ +>step : Symbol(step, Decl(generatorYieldContextualType.ts, 107, 7)) +>QuickPickStep : Symbol(QuickPickStep, Decl(generatorYieldContextualType.ts, 38, 1)) +>QuickPickItem : Symbol(QuickPickItem, Decl(generatorYieldContextualType.ts, 24, 1)) +>createPickStep : Symbol(createPickStep, Decl(generatorYieldContextualType.ts, 95, 1)) +>QuickPickItem : Symbol(QuickPickItem, Decl(generatorYieldContextualType.ts, 24, 1)) + + title: "", +>title : Symbol(title, Decl(generatorYieldContextualType.ts, 107, 76)) + + placeholder: "", +>placeholder : Symbol(placeholder, Decl(generatorYieldContextualType.ts, 108, 14)) + + }); + const selection: StepSelection = yield step; +>selection : Symbol(selection, Decl(generatorYieldContextualType.ts, 111, 7)) +>StepSelection : Symbol(StepSelection, Decl(generatorYieldContextualType.ts, 72, 6)) +>step : Symbol(step, Decl(generatorYieldContextualType.ts, 107, 7)) +>step : Symbol(step, Decl(generatorYieldContextualType.ts, 107, 7)) + + return canPickStepContinue(step, state, selection) +>canPickStepContinue : Symbol(canPickStepContinue, Decl(generatorYieldContextualType.ts, 87, 2)) +>step : Symbol(step, Decl(generatorYieldContextualType.ts, 107, 7)) +>state : Symbol(state, Decl(generatorYieldContextualType.ts, 106, 2)) +>selection : Symbol(selection, Decl(generatorYieldContextualType.ts, 111, 7)) + + ? selection[0] +>selection : Symbol(selection, Decl(generatorYieldContextualType.ts, 111, 7)) + + : StepResult.Break; +>StepResult.Break : Symbol(StepResult.Break, Decl(generatorYieldContextualType.ts, 63, 14)) +>StepResult : Symbol(StepResult, Decl(generatorYieldContextualType.ts, 61, 10), Decl(generatorYieldContextualType.ts, 64, 1)) +>Break : Symbol(StepResult.Break, Decl(generatorYieldContextualType.ts, 63, 14)) +} + diff --git a/tests/baselines/reference/generatorYieldContextualType.types b/tests/baselines/reference/generatorYieldContextualType.types index a90bbd040a1cb..dfc7c4f858c67 100644 --- a/tests/baselines/reference/generatorYieldContextualType.types +++ b/tests/baselines/reference/generatorYieldContextualType.types @@ -36,3 +36,240 @@ f2<0, 0, 1>(async function* () { >0 : 0 }); + +// repro from #41428 +enum Directive { +>Directive : Directive + + Back, +>Back : Directive.Back + + Cancel, +>Cancel : Directive.Cancel + + LoadMore, +>LoadMore : Directive.LoadMore + + Noop, +>Noop : Directive.Noop +} + +namespace Directive { +>Directive : typeof Directive + + export function is(value: Directive | T): value is Directive { +>is : (value: Directive | T) => value is Directive +>value : T | Directive + + return typeof value === "number" && Directive[value] != null; +>typeof value === "number" && Directive[value] != null : boolean +>typeof value === "number" : boolean +>typeof value : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>value : T | Directive +>"number" : "number" +>Directive[value] != null : boolean +>Directive[value] : (typeof Directive)[Directive | (T & number)] +>Directive : typeof Directive +>value : Directive | (T & number) +>null : null + } +} + +interface QuickPickItem { + label: string; +>label : string + + description?: string; +>description : string | undefined + + detail?: string; +>detail : string | undefined + + picked?: boolean; +>picked : boolean | undefined + + alwaysShow?: boolean; +>alwaysShow : boolean | undefined +} + +interface QuickInputStep { + placeholder?: string; +>placeholder : string | undefined + + prompt?: string; +>prompt : string | undefined + + title?: string; +>title : string | undefined +} + +interface QuickPickStep { + placeholder?: string; +>placeholder : string | undefined + + title?: string; +>title : string | undefined +} + +type StepGenerator = +>StepGenerator : Generator, StepResult, any> | AsyncGenerator, StepResult, any> + + | Generator< + QuickPickStep | QuickInputStep, + StepResult, + any | undefined + > + | AsyncGenerator< + QuickPickStep | QuickInputStep, + StepResult, + any | undefined + >; + +type StepItemType = T extends QuickPickStep +>StepItemType : StepItemType + + ? U[] + : T extends QuickInputStep + ? string + : never; +namespace StepResult { +>StepResult : typeof StepResult + + export const Break = Symbol("BreakStep"); +>Break : unique symbol +>Symbol("BreakStep") : unique symbol +>Symbol : SymbolConstructor +>"BreakStep" : "BreakStep" +} +type StepResult = typeof StepResult.Break | T; +>StepResult : StepResult +>StepResult.Break : unique symbol +>StepResult : typeof StepResult +>Break : unique symbol + +type StepResultGenerator = +>StepResultGenerator : StepResultGenerator + + | Generator, any | undefined> + | AsyncGenerator< + QuickPickStep | QuickInputStep, + StepResult, + any | undefined + >; +type StepSelection = T extends QuickPickStep +>StepSelection : StepSelection + + ? U[] | Directive + : T extends QuickInputStep + ? string | Directive + : never; +type PartialStepState = Partial & { +>PartialStepState : PartialStepState + + counter: number; +>counter : number + + confirm?: boolean; +>confirm : boolean | undefined + + startingStep?: number; +>startingStep : number | undefined + +}; +type StepState> = T & { +>StepState : StepState + + counter: number; +>counter : number + + confirm?: boolean; +>confirm : boolean | undefined + + startingStep?: number; +>startingStep : number | undefined + +}; + +function canPickStepContinue( +>canPickStepContinue : >(_step: T, _state: PartialStepState, _selection: StepItemType | Directive) => _selection is StepItemType + + _step: T, +>_step : T + + _state: PartialStepState, +>_state : PartialStepState + + _selection: StepItemType | Directive +>_selection : Directive | StepItemType + +): _selection is StepItemType { + return false; +>false : false +} + +function createPickStep( +>createPickStep : (step: QuickPickStep) => QuickPickStep + + step: QuickPickStep +>step : QuickPickStep + +): QuickPickStep { + return step; +>step : QuickPickStep +} + +function* showStep< +>showStep : & { counter: number; confirm?: boolean | undefined; startingStep?: number | undefined; } & { repo: any; }, Context extends { repos: any[]; title: string; status: any; }>(state: State, _context: Context) => StepResultGenerator + + State extends PartialStepState & { repo: any }, +>repo : any + + Context extends { repos: any[]; title: string; status: any } +>repos : any[] +>title : string +>status : any + +>(state: State, _context: Context): StepResultGenerator { +>state : State +>_context : Context + + const step: QuickPickStep = createPickStep({ +>step : QuickPickStep +>createPickStep({ title: "", placeholder: "", }) : QuickPickStep +>createPickStep : (step: QuickPickStep) => QuickPickStep +>{ title: "", placeholder: "", } : { title: string; placeholder: string; } + + title: "", +>title : string +>"" : "" + + placeholder: "", +>placeholder : string +>"" : "" + + }); + const selection: StepSelection = yield step; +>selection : Directive | QuickPickItem[] +>step : QuickPickStep +>yield step : any +>step : QuickPickStep + + return canPickStepContinue(step, state, selection) +>canPickStepContinue(step, state, selection) ? selection[0] : StepResult.Break : QuickPickItem | unique symbol +>canPickStepContinue(step, state, selection) : boolean +>canPickStepContinue : >(_step: T, _state: PartialStepState, _selection: Directive | StepItemType) => _selection is StepItemType +>step : QuickPickStep +>state : State +>selection : Directive | QuickPickItem[] + + ? selection[0] +>selection[0] : QuickPickItem +>selection : QuickPickItem[] +>0 : 0 + + : StepResult.Break; +>StepResult.Break : unique symbol +>StepResult : typeof StepResult +>Break : unique symbol +} + diff --git a/tests/cases/conformance/generators/generatorYieldContextualType.ts b/tests/cases/conformance/generators/generatorYieldContextualType.ts index 20cad6a91893c..514583c1c5ea7 100644 --- a/tests/cases/conformance/generators/generatorYieldContextualType.ts +++ b/tests/cases/conformance/generators/generatorYieldContextualType.ts @@ -11,4 +11,109 @@ declare function f2(gen: () => Generator | AsyncGenerator(async function* () { const a = yield 0; return 0; -}); \ No newline at end of file +}); + +// repro from #41428 +enum Directive { + Back, + Cancel, + LoadMore, + Noop, +} + +namespace Directive { + export function is(value: Directive | T): value is Directive { + return typeof value === "number" && Directive[value] != null; + } +} + +interface QuickPickItem { + label: string; + description?: string; + detail?: string; + picked?: boolean; + alwaysShow?: boolean; +} + +interface QuickInputStep { + placeholder?: string; + prompt?: string; + title?: string; +} + +interface QuickPickStep { + placeholder?: string; + title?: string; +} + +type StepGenerator = + | Generator< + QuickPickStep | QuickInputStep, + StepResult, + any | undefined + > + | AsyncGenerator< + QuickPickStep | QuickInputStep, + StepResult, + any | undefined + >; + +type StepItemType = T extends QuickPickStep + ? U[] + : T extends QuickInputStep + ? string + : never; +namespace StepResult { + export const Break = Symbol("BreakStep"); +} +type StepResult = typeof StepResult.Break | T; +type StepResultGenerator = + | Generator, any | undefined> + | AsyncGenerator< + QuickPickStep | QuickInputStep, + StepResult, + any | undefined + >; +type StepSelection = T extends QuickPickStep + ? U[] | Directive + : T extends QuickInputStep + ? string | Directive + : never; +type PartialStepState = Partial & { + counter: number; + confirm?: boolean; + startingStep?: number; +}; +type StepState> = T & { + counter: number; + confirm?: boolean; + startingStep?: number; +}; + +function canPickStepContinue( + _step: T, + _state: PartialStepState, + _selection: StepItemType | Directive +): _selection is StepItemType { + return false; +} + +function createPickStep( + step: QuickPickStep +): QuickPickStep { + return step; +} + +function* showStep< + State extends PartialStepState & { repo: any }, + Context extends { repos: any[]; title: string; status: any } +>(state: State, _context: Context): StepResultGenerator { + const step: QuickPickStep = createPickStep({ + title: "", + placeholder: "", + }); + const selection: StepSelection = yield step; + return canPickStepContinue(step, state, selection) + ? selection[0] + : StepResult.Break; +} From 517f1d5e00eebc15208fce63b6cf273faa643200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 25 May 2023 22:10:43 +0200 Subject: [PATCH 4/7] Avoid calling filterType when not needed --- src/compiler/checker.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 687717fd71b10..14bd5891d4950 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28933,16 +28933,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const signature = getContextualSignatureForFunctionLikeDeclaration(functionDecl as FunctionExpression); if (signature && !isResolvingReturnTypeOfSignature(signature)) { const functionFlags = getFunctionFlags(functionDecl); - - return filterType(getReturnTypeOfSignature(signature), returnType => { - if (functionFlags & FunctionFlags.Generator) { - return checkGeneratorInstantiationAssignabilityToReturnType(returnType, functionFlags, /*errorNode*/ undefined); - } - if (functionFlags & FunctionFlags.Async) { - return !!getAwaitedTypeOfPromise(returnType); - } - return true; - }); + const returnType = getReturnTypeOfSignature(signature); + if (functionFlags & FunctionFlags.Generator) { + return filterType(returnType, t => checkGeneratorInstantiationAssignabilityToReturnType(t, functionFlags, /*errorNode*/ undefined)); + } + if (functionFlags & FunctionFlags.Async) { + return filterType(returnType, t => !!getAwaitedTypeOfPromise(t)); + } + return returnType; } const iife = getImmediatelyInvokedFunctionExpression(functionDecl); if (iife) { From 1784567c010a60724ac692f6492f1b0d1c332f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 27 May 2023 07:31:01 +0200 Subject: [PATCH 5/7] skip over any and void --- src/compiler/checker.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 14bd5891d4950..9a488036e1525 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28932,8 +28932,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and that call signature is non-generic, return statements are contextually typed by the return type of the signature const signature = getContextualSignatureForFunctionLikeDeclaration(functionDecl as FunctionExpression); if (signature && !isResolvingReturnTypeOfSignature(signature)) { - const functionFlags = getFunctionFlags(functionDecl); const returnType = getReturnTypeOfSignature(signature); + if (returnType.flags & (TypeFlags.Any | TypeFlags.Void)) { + return returnType; + } + const functionFlags = getFunctionFlags(functionDecl); if (functionFlags & FunctionFlags.Generator) { return filterType(returnType, t => checkGeneratorInstantiationAssignabilityToReturnType(t, functionFlags, /*errorNode*/ undefined)); } From 3f1ee89cdf2a3728c65a6812729c2c448eb1dd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 29 May 2023 13:49:57 +0200 Subject: [PATCH 6/7] tweak code, add tests --- src/compiler/checker.ts | 11 +- ...xtuallyTypeAsyncFunctionReturnType.symbols | 179 ++++++++++++++++++ ...textuallyTypeAsyncFunctionReturnType.types | 176 +++++++++++++++++ .../noImplicitReturnsExclusions.errors.txt | 41 +++- .../noImplicitReturnsExclusions.symbols | 113 +++++++++++ .../noImplicitReturnsExclusions.types | 95 ++++++++++ .../compiler/noImplicitReturnsExclusions.ts | 36 ++++ ...contextuallyTypeAsyncFunctionReturnType.ts | 65 ++++++- 8 files changed, 709 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9a488036e1525..b9cdb0e074f8d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28933,15 +28933,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const signature = getContextualSignatureForFunctionLikeDeclaration(functionDecl as FunctionExpression); if (signature && !isResolvingReturnTypeOfSignature(signature)) { const returnType = getReturnTypeOfSignature(signature); - if (returnType.flags & (TypeFlags.Any | TypeFlags.Void)) { - return returnType; - } const functionFlags = getFunctionFlags(functionDecl); if (functionFlags & FunctionFlags.Generator) { - return filterType(returnType, t => checkGeneratorInstantiationAssignabilityToReturnType(t, functionFlags, /*errorNode*/ undefined)); + return filterType(returnType, t => { + return !!(t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.InstantiableNonPrimitive)) || checkGeneratorInstantiationAssignabilityToReturnType(t, functionFlags, /*errorNode*/ undefined); + }); } if (functionFlags & FunctionFlags.Async) { - return filterType(returnType, t => !!getAwaitedTypeOfPromise(t)); + return filterType(returnType, t => { + return !!(t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.InstantiableNonPrimitive)) || !!getAwaitedTypeOfPromise(t); + }); } return returnType; } diff --git a/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnType.symbols b/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnType.symbols index e85fa4d0d9ac2..69fc350504c7f 100644 --- a/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnType.symbols +++ b/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnType.symbols @@ -52,3 +52,182 @@ async function fn4(): Promise { }); } + +declare class Context { +>Context : Symbol(Context, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 20, 1)) + + private _runnable; +>_runnable : Symbol(Context._runnable, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 22, 23)) +} +type Done = (err?: any) => void; +>Done : Symbol(Done, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 24, 1)) +>err : Symbol(err, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 25, 13)) + +type Func = (this: Context, done: Done) => void; +>Func : Symbol(Func, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 25, 32)) +>this : Symbol(this, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 26, 13)) +>Context : Symbol(Context, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 20, 1)) +>done : Symbol(done, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 26, 27)) +>Done : Symbol(Done, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 24, 1)) + +type AsyncFunc = (this: Context) => PromiseLike; +>AsyncFunc : Symbol(AsyncFunc, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 26, 48)) +>this : Symbol(this, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 27, 18)) +>Context : Symbol(Context, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 20, 1)) +>PromiseLike : Symbol(PromiseLike, Decl(lib.es5.d.ts, --, --)) + +interface TestFunction { +>TestFunction : Symbol(TestFunction, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 27, 53)) + + (fn: Func): void; +>fn : Symbol(fn, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 30, 3)) +>Func : Symbol(Func, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 25, 32)) + + (fn: AsyncFunc): void; +>fn : Symbol(fn, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 31, 3)) +>AsyncFunc : Symbol(AsyncFunc, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 26, 48)) + + (title: string, fn?: Func): void; +>title : Symbol(title, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 32, 3)) +>fn : Symbol(fn, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 32, 17)) +>Func : Symbol(Func, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 25, 32)) + + (title: string, fn?: AsyncFunc): void; +>title : Symbol(title, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 33, 3)) +>fn : Symbol(fn, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 33, 17)) +>AsyncFunc : Symbol(AsyncFunc, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 26, 48)) +} + +declare const test: TestFunction; +>test : Symbol(test, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 36, 13)) +>TestFunction : Symbol(TestFunction, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 27, 53)) + +interface ProcessTreeNode { +>ProcessTreeNode : Symbol(ProcessTreeNode, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 36, 33)) + + pid: number; +>pid : Symbol(ProcessTreeNode.pid, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 38, 27)) + + name: string; +>name : Symbol(ProcessTreeNode.name, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 39, 14)) + + memory?: number; +>memory : Symbol(ProcessTreeNode.memory, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 40, 15)) + + commandLine?: string; +>commandLine : Symbol(ProcessTreeNode.commandLine, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 41, 18)) + + children: ProcessTreeNode[]; +>children : Symbol(ProcessTreeNode.children, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 42, 23)) +>ProcessTreeNode : Symbol(ProcessTreeNode, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 36, 33)) +} + +export declare function getProcessTree( +>getProcessTree : Symbol(getProcessTree, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 44, 1)) + + rootPid: number, +>rootPid : Symbol(rootPid, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 46, 39)) + + callback: (tree: ProcessTreeNode) => void +>callback : Symbol(callback, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 47, 18)) +>tree : Symbol(tree, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 48, 13)) +>ProcessTreeNode : Symbol(ProcessTreeNode, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 36, 33)) + +): void; + +test("windows-process-tree", async () => { +>test : Symbol(test, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 36, 13)) + + return new Promise((resolve, reject) => { +>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, --, --)) +>resolve : Symbol(resolve, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 52, 22)) +>reject : Symbol(reject, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 52, 30)) + + getProcessTree(123, (tree) => { +>getProcessTree : Symbol(getProcessTree, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 44, 1)) +>tree : Symbol(tree, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 53, 25)) + + if (tree) { +>tree : Symbol(tree, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 53, 25)) + + resolve(); +>resolve : Symbol(resolve, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 52, 22)) + + } else { + reject(new Error("windows-process-tree")); +>reject : Symbol(reject, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 52, 30)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --)) + } + }); + }); +}); + +interface ILocalExtension { +>ILocalExtension : Symbol(ILocalExtension, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 61, 3)) + + isApplicationScoped: boolean; +>isApplicationScoped : Symbol(ILocalExtension.isApplicationScoped, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 63, 27)) + + publisherId: string | null; +>publisherId : Symbol(ILocalExtension.publisherId, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 64, 31)) +} +type Metadata = { +>Metadata : Symbol(Metadata, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 66, 1)) + + updated: boolean; +>updated : Symbol(updated, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 67, 17)) + +}; +declare function scanMetadata( +>scanMetadata : Symbol(scanMetadata, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 69, 2)) + + local: ILocalExtension +>local : Symbol(local, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 70, 30)) +>ILocalExtension : Symbol(ILocalExtension, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 61, 3)) + +): Promise; +>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, --, --)) +>Metadata : Symbol(Metadata, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 66, 1)) + +async function copyExtensions( +>copyExtensions : Symbol(copyExtensions, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 72, 33)) + + fromExtensions: ILocalExtension[] +>fromExtensions : Symbol(fromExtensions, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 74, 30)) +>ILocalExtension : Symbol(ILocalExtension, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 61, 3)) + +): Promise { +>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, --, --)) + + const extensions: [ILocalExtension, Metadata | undefined][] = +>extensions : Symbol(extensions, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 77, 7)) +>ILocalExtension : Symbol(ILocalExtension, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 61, 3)) +>Metadata : Symbol(Metadata, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 66, 1)) + + await Promise.all( +>Promise.all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>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, --, --)) +>all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) + + fromExtensions +>fromExtensions .filter((e) => !e.isApplicationScoped) .map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>fromExtensions .filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>fromExtensions : Symbol(fromExtensions, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 74, 30)) + + .filter((e) => !e.isApplicationScoped) +>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>e : Symbol(e, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 80, 17)) +>e.isApplicationScoped : Symbol(ILocalExtension.isApplicationScoped, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 63, 27)) +>e : Symbol(e, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 80, 17)) +>isApplicationScoped : Symbol(ILocalExtension.isApplicationScoped, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 63, 27)) + + .map(async (e) => [e, await scanMetadata(e)]) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>e : Symbol(e, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 81, 20)) +>e : Symbol(e, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 81, 20)) +>scanMetadata : Symbol(scanMetadata, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 69, 2)) +>e : Symbol(e, Decl(contextuallyTypeAsyncFunctionReturnType.ts, 81, 20)) + + ); +} + diff --git a/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnType.types b/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnType.types index 77aa15a8b085a..671fc12d97019 100644 --- a/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnType.types +++ b/tests/baselines/reference/contextuallyTypeAsyncFunctionReturnType.types @@ -59,3 +59,179 @@ async function fn4(): Promise { }); } + +declare class Context { +>Context : Context + + private _runnable; +>_runnable : any +} +type Done = (err?: any) => void; +>Done : (err?: any) => void +>err : any + +type Func = (this: Context, done: Done) => void; +>Func : (this: Context, done: Done) => void +>this : Context +>done : Done + +type AsyncFunc = (this: Context) => PromiseLike; +>AsyncFunc : (this: Context) => PromiseLike +>this : Context + +interface TestFunction { + (fn: Func): void; +>fn : Func + + (fn: AsyncFunc): void; +>fn : AsyncFunc + + (title: string, fn?: Func): void; +>title : string +>fn : Func + + (title: string, fn?: AsyncFunc): void; +>title : string +>fn : AsyncFunc +} + +declare const test: TestFunction; +>test : TestFunction + +interface ProcessTreeNode { + pid: number; +>pid : number + + name: string; +>name : string + + memory?: number; +>memory : number + + commandLine?: string; +>commandLine : string + + children: ProcessTreeNode[]; +>children : ProcessTreeNode[] +} + +export declare function getProcessTree( +>getProcessTree : (rootPid: number, callback: (tree: ProcessTreeNode) => void) => void + + rootPid: number, +>rootPid : number + + callback: (tree: ProcessTreeNode) => void +>callback : (tree: ProcessTreeNode) => void +>tree : ProcessTreeNode + +): void; + +test("windows-process-tree", async () => { +>test("windows-process-tree", async () => { return new Promise((resolve, reject) => { getProcessTree(123, (tree) => { if (tree) { resolve(); } else { reject(new Error("windows-process-tree")); } }); });}) : void +>test : TestFunction +>"windows-process-tree" : "windows-process-tree" +>async () => { return new Promise((resolve, reject) => { getProcessTree(123, (tree) => { if (tree) { resolve(); } else { reject(new Error("windows-process-tree")); } }); });} : () => Promise + + return new Promise((resolve, reject) => { +>new Promise((resolve, reject) => { getProcessTree(123, (tree) => { if (tree) { resolve(); } else { reject(new Error("windows-process-tree")); } }); }) : Promise +>Promise : PromiseConstructor +>(resolve, reject) => { getProcessTree(123, (tree) => { if (tree) { resolve(); } else { reject(new Error("windows-process-tree")); } }); } : (resolve: (value: void | PromiseLike) => void, reject: (reason?: any) => void) => void +>resolve : (value: void | PromiseLike) => void +>reject : (reason?: any) => void + + getProcessTree(123, (tree) => { +>getProcessTree(123, (tree) => { if (tree) { resolve(); } else { reject(new Error("windows-process-tree")); } }) : void +>getProcessTree : (rootPid: number, callback: (tree: ProcessTreeNode) => void) => void +>123 : 123 +>(tree) => { if (tree) { resolve(); } else { reject(new Error("windows-process-tree")); } } : (tree: ProcessTreeNode) => void +>tree : ProcessTreeNode + + if (tree) { +>tree : ProcessTreeNode + + resolve(); +>resolve() : void +>resolve : (value: void | PromiseLike) => void + + } else { + reject(new Error("windows-process-tree")); +>reject(new Error("windows-process-tree")) : void +>reject : (reason?: any) => void +>new Error("windows-process-tree") : Error +>Error : ErrorConstructor +>"windows-process-tree" : "windows-process-tree" + } + }); + }); +}); + +interface ILocalExtension { + isApplicationScoped: boolean; +>isApplicationScoped : boolean + + publisherId: string | null; +>publisherId : string +} +type Metadata = { +>Metadata : { updated: boolean; } + + updated: boolean; +>updated : boolean + +}; +declare function scanMetadata( +>scanMetadata : (local: ILocalExtension) => Promise + + local: ILocalExtension +>local : ILocalExtension + +): Promise; + +async function copyExtensions( +>copyExtensions : (fromExtensions: ILocalExtension[]) => Promise + + fromExtensions: ILocalExtension[] +>fromExtensions : ILocalExtension[] + +): Promise { + const extensions: [ILocalExtension, Metadata | undefined][] = +>extensions : [ILocalExtension, Metadata][] + + await Promise.all( +>await Promise.all( fromExtensions .filter((e) => !e.isApplicationScoped) .map(async (e) => [e, await scanMetadata(e)]) ) : [ILocalExtension, Metadata][] +>Promise.all( fromExtensions .filter((e) => !e.isApplicationScoped) .map(async (e) => [e, await scanMetadata(e)]) ) : Promise<[ILocalExtension, Metadata][]> +>Promise.all : { (values: Iterable>): Promise[]>; (values: T): Promise<{ -readonly [P in keyof T]: Awaited; }>; } +>Promise : PromiseConstructor +>all : { (values: Iterable>): Promise[]>; (values: T): Promise<{ -readonly [P in keyof T]: Awaited; }>; } + + fromExtensions +>fromExtensions .filter((e) => !e.isApplicationScoped) .map(async (e) => [e, await scanMetadata(e)]) : Promise<[ILocalExtension, Metadata]>[] +>fromExtensions .filter((e) => !e.isApplicationScoped) .map : (callbackfn: (value: ILocalExtension, index: number, array: ILocalExtension[]) => U, thisArg?: any) => U[] +>fromExtensions .filter((e) => !e.isApplicationScoped) : ILocalExtension[] +>fromExtensions .filter : { (predicate: (value: ILocalExtension, index: number, array: ILocalExtension[]) => value is S, thisArg?: any): S[]; (predicate: (value: ILocalExtension, index: number, array: ILocalExtension[]) => unknown, thisArg?: any): ILocalExtension[]; } +>fromExtensions : ILocalExtension[] + + .filter((e) => !e.isApplicationScoped) +>filter : { (predicate: (value: ILocalExtension, index: number, array: ILocalExtension[]) => value is S, thisArg?: any): S[]; (predicate: (value: ILocalExtension, index: number, array: ILocalExtension[]) => unknown, thisArg?: any): ILocalExtension[]; } +>(e) => !e.isApplicationScoped : (e: ILocalExtension) => boolean +>e : ILocalExtension +>!e.isApplicationScoped : boolean +>e.isApplicationScoped : boolean +>e : ILocalExtension +>isApplicationScoped : boolean + + .map(async (e) => [e, await scanMetadata(e)]) +>map : (callbackfn: (value: ILocalExtension, index: number, array: ILocalExtension[]) => U, thisArg?: any) => U[] +>async (e) => [e, await scanMetadata(e)] : (e: ILocalExtension) => Promise<[ILocalExtension, Metadata]> +>e : ILocalExtension +>[e, await scanMetadata(e)] : [ILocalExtension, Metadata] +>e : ILocalExtension +>await scanMetadata(e) : Metadata +>scanMetadata(e) : Promise +>scanMetadata : (local: ILocalExtension) => Promise +>e : ILocalExtension + + ); +} + diff --git a/tests/baselines/reference/noImplicitReturnsExclusions.errors.txt b/tests/baselines/reference/noImplicitReturnsExclusions.errors.txt index 74a54748f2c20..bb71ec53f9721 100644 --- a/tests/baselines/reference/noImplicitReturnsExclusions.errors.txt +++ b/tests/baselines/reference/noImplicitReturnsExclusions.errors.txt @@ -4,9 +4,10 @@ tests/cases/compiler/noImplicitReturnsExclusions.ts(40,10): error TS7030: Not al tests/cases/compiler/noImplicitReturnsExclusions.ts(44,10): error TS7030: Not all code paths return a value. tests/cases/compiler/noImplicitReturnsExclusions.ts(48,10): error TS7030: Not all code paths return a value. tests/cases/compiler/noImplicitReturnsExclusions.ts(53,10): error TS7030: Not all code paths return a value. +tests/cases/compiler/noImplicitReturnsExclusions.ts(88,53): error TS7030: Not all code paths return a value. -==== tests/cases/compiler/noImplicitReturnsExclusions.ts (6 errors) ==== +==== tests/cases/compiler/noImplicitReturnsExclusions.ts (7 errors) ==== // Functions with a return type of any, undefined, or a type that includes void are excluded // from --noImplicitReturns checks. @@ -75,4 +76,42 @@ tests/cases/compiler/noImplicitReturnsExclusions.ts(53,10): error TS7030: Not al if (b) return 42; if (b) return; } + + declare class HistoryItem { + input: { + location: { + uri: string; + }; + }; + } + + interface Thenable { + then( + onfulfilled?: (value: T) => TResult | Thenable, + onrejected?: (reason: any) => TResult | Thenable + ): Thenable; + then( + onfulfilled?: (value: T) => TResult | Thenable, + onrejected?: (reason: any) => void + ): Thenable; + } + + export declare function executeCommand( + command: string, + ...rest: any[] + ): Thenable; + + export declare function registerCommand( + command: string, + callback: (...args: any[]) => any, + thisArg?: any + ): void; + + registerCommand("_references-view.showHistoryItem", async (item) => { // Error, contextual return type of Promise + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS7030: Not all code paths return a value. + if (item instanceof HistoryItem) { + return executeCommand("vscode.open", item.input.location.uri); + } + }); \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitReturnsExclusions.symbols b/tests/baselines/reference/noImplicitReturnsExclusions.symbols index 56a3eea64f5cb..b545fa2627dbd 100644 --- a/tests/baselines/reference/noImplicitReturnsExclusions.symbols +++ b/tests/baselines/reference/noImplicitReturnsExclusions.symbols @@ -122,3 +122,116 @@ function f16(b: boolean) { // Error >b : Symbol(b, Decl(noImplicitReturnsExclusions.ts, 52, 13)) } +declare class HistoryItem { +>HistoryItem : Symbol(HistoryItem, Decl(noImplicitReturnsExclusions.ts, 55, 1)) + + input: { +>input : Symbol(HistoryItem.input, Decl(noImplicitReturnsExclusions.ts, 57, 27)) + + location: { +>location : Symbol(location, Decl(noImplicitReturnsExclusions.ts, 58, 10)) + + uri: string; +>uri : Symbol(uri, Decl(noImplicitReturnsExclusions.ts, 59, 15)) + + }; + }; +} + +interface Thenable { +>Thenable : Symbol(Thenable, Decl(noImplicitReturnsExclusions.ts, 63, 1)) +>T : Symbol(T, Decl(noImplicitReturnsExclusions.ts, 65, 19)) + + then( +>then : Symbol(Thenable.then, Decl(noImplicitReturnsExclusions.ts, 65, 23), Decl(noImplicitReturnsExclusions.ts, 69, 23)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 66, 7)) + + onfulfilled?: (value: T) => TResult | Thenable, +>onfulfilled : Symbol(onfulfilled, Decl(noImplicitReturnsExclusions.ts, 66, 16)) +>value : Symbol(value, Decl(noImplicitReturnsExclusions.ts, 67, 19)) +>T : Symbol(T, Decl(noImplicitReturnsExclusions.ts, 65, 19)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 66, 7)) +>Thenable : Symbol(Thenable, Decl(noImplicitReturnsExclusions.ts, 63, 1)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 66, 7)) + + onrejected?: (reason: any) => TResult | Thenable +>onrejected : Symbol(onrejected, Decl(noImplicitReturnsExclusions.ts, 67, 60)) +>reason : Symbol(reason, Decl(noImplicitReturnsExclusions.ts, 68, 18)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 66, 7)) +>Thenable : Symbol(Thenable, Decl(noImplicitReturnsExclusions.ts, 63, 1)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 66, 7)) + + ): Thenable; +>Thenable : Symbol(Thenable, Decl(noImplicitReturnsExclusions.ts, 63, 1)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 66, 7)) + + then( +>then : Symbol(Thenable.then, Decl(noImplicitReturnsExclusions.ts, 65, 23), Decl(noImplicitReturnsExclusions.ts, 69, 23)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 70, 7)) + + onfulfilled?: (value: T) => TResult | Thenable, +>onfulfilled : Symbol(onfulfilled, Decl(noImplicitReturnsExclusions.ts, 70, 16)) +>value : Symbol(value, Decl(noImplicitReturnsExclusions.ts, 71, 19)) +>T : Symbol(T, Decl(noImplicitReturnsExclusions.ts, 65, 19)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 70, 7)) +>Thenable : Symbol(Thenable, Decl(noImplicitReturnsExclusions.ts, 63, 1)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 70, 7)) + + onrejected?: (reason: any) => void +>onrejected : Symbol(onrejected, Decl(noImplicitReturnsExclusions.ts, 71, 60)) +>reason : Symbol(reason, Decl(noImplicitReturnsExclusions.ts, 72, 18)) + + ): Thenable; +>Thenable : Symbol(Thenable, Decl(noImplicitReturnsExclusions.ts, 63, 1)) +>TResult : Symbol(TResult, Decl(noImplicitReturnsExclusions.ts, 70, 7)) +} + +export declare function executeCommand( +>executeCommand : Symbol(executeCommand, Decl(noImplicitReturnsExclusions.ts, 74, 1)) +>T : Symbol(T, Decl(noImplicitReturnsExclusions.ts, 76, 39)) + + command: string, +>command : Symbol(command, Decl(noImplicitReturnsExclusions.ts, 76, 52)) + + ...rest: any[] +>rest : Symbol(rest, Decl(noImplicitReturnsExclusions.ts, 77, 18)) + +): Thenable; +>Thenable : Symbol(Thenable, Decl(noImplicitReturnsExclusions.ts, 63, 1)) +>T : Symbol(T, Decl(noImplicitReturnsExclusions.ts, 76, 39)) + +export declare function registerCommand( +>registerCommand : Symbol(registerCommand, Decl(noImplicitReturnsExclusions.ts, 79, 15)) + + command: string, +>command : Symbol(command, Decl(noImplicitReturnsExclusions.ts, 81, 40)) + + callback: (...args: any[]) => any, +>callback : Symbol(callback, Decl(noImplicitReturnsExclusions.ts, 82, 18)) +>args : Symbol(args, Decl(noImplicitReturnsExclusions.ts, 83, 13)) + + thisArg?: any +>thisArg : Symbol(thisArg, Decl(noImplicitReturnsExclusions.ts, 83, 36)) + +): void; + +registerCommand("_references-view.showHistoryItem", async (item) => { // Error, contextual return type of Promise +>registerCommand : Symbol(registerCommand, Decl(noImplicitReturnsExclusions.ts, 79, 15)) +>item : Symbol(item, Decl(noImplicitReturnsExclusions.ts, 87, 59)) + + if (item instanceof HistoryItem) { +>item : Symbol(item, Decl(noImplicitReturnsExclusions.ts, 87, 59)) +>HistoryItem : Symbol(HistoryItem, Decl(noImplicitReturnsExclusions.ts, 55, 1)) + + return executeCommand("vscode.open", item.input.location.uri); +>executeCommand : Symbol(executeCommand, Decl(noImplicitReturnsExclusions.ts, 74, 1)) +>item.input.location.uri : Symbol(uri, Decl(noImplicitReturnsExclusions.ts, 59, 15)) +>item.input.location : Symbol(location, Decl(noImplicitReturnsExclusions.ts, 58, 10)) +>item.input : Symbol(HistoryItem.input, Decl(noImplicitReturnsExclusions.ts, 57, 27)) +>item : Symbol(item, Decl(noImplicitReturnsExclusions.ts, 87, 59)) +>input : Symbol(HistoryItem.input, Decl(noImplicitReturnsExclusions.ts, 57, 27)) +>location : Symbol(location, Decl(noImplicitReturnsExclusions.ts, 58, 10)) +>uri : Symbol(uri, Decl(noImplicitReturnsExclusions.ts, 59, 15)) + } +}); + diff --git a/tests/baselines/reference/noImplicitReturnsExclusions.types b/tests/baselines/reference/noImplicitReturnsExclusions.types index a0c44c8afbb6e..b6c14c20cdfa5 100644 --- a/tests/baselines/reference/noImplicitReturnsExclusions.types +++ b/tests/baselines/reference/noImplicitReturnsExclusions.types @@ -127,3 +127,98 @@ function f16(b: boolean) { // Error >b : false } +declare class HistoryItem { +>HistoryItem : HistoryItem + + input: { +>input : { location: { uri: string;}; } + + location: { +>location : { uri: string; } + + uri: string; +>uri : string + + }; + }; +} + +interface Thenable { + then( +>then : { (onfulfilled?: ((value: T) => TResult | Thenable) | undefined, onrejected?: ((reason: any) => TResult | Thenable) | undefined): Thenable; (onfulfilled?: ((value: T) => TResult | Thenable) | undefined, onrejected?: ((reason: any) => void) | undefined): Thenable; } + + onfulfilled?: (value: T) => TResult | Thenable, +>onfulfilled : ((value: T) => TResult | Thenable) | undefined +>value : T + + onrejected?: (reason: any) => TResult | Thenable +>onrejected : ((reason: any) => TResult | Thenable) | undefined +>reason : any + + ): Thenable; + then( +>then : { (onfulfilled?: ((value: T) => TResult | Thenable) | undefined, onrejected?: ((reason: any) => TResult | Thenable) | undefined): Thenable; (onfulfilled?: ((value: T) => TResult | Thenable) | undefined, onrejected?: ((reason: any) => void) | undefined): Thenable; } + + onfulfilled?: (value: T) => TResult | Thenable, +>onfulfilled : ((value: T) => TResult | Thenable) | undefined +>value : T + + onrejected?: (reason: any) => void +>onrejected : ((reason: any) => void) | undefined +>reason : any + + ): Thenable; +} + +export declare function executeCommand( +>executeCommand : (command: string, ...rest: any[]) => Thenable + + command: string, +>command : string + + ...rest: any[] +>rest : any[] + +): Thenable; + +export declare function registerCommand( +>registerCommand : (command: string, callback: (...args: any[]) => any, thisArg?: any) => void + + command: string, +>command : string + + callback: (...args: any[]) => any, +>callback : (...args: any[]) => any +>args : any[] + + thisArg?: any +>thisArg : any + +): void; + +registerCommand("_references-view.showHistoryItem", async (item) => { // Error, contextual return type of Promise +>registerCommand("_references-view.showHistoryItem", async (item) => { // Error, contextual return type of Promise if (item instanceof HistoryItem) { return executeCommand("vscode.open", item.input.location.uri); }}) : void +>registerCommand : (command: string, callback: (...args: any[]) => any, thisArg?: any) => void +>"_references-view.showHistoryItem" : "_references-view.showHistoryItem" +>async (item) => { // Error, contextual return type of Promise if (item instanceof HistoryItem) { return executeCommand("vscode.open", item.input.location.uri); }} : (item: any) => Promise +>item : any + + if (item instanceof HistoryItem) { +>item instanceof HistoryItem : boolean +>item : any +>HistoryItem : typeof HistoryItem + + return executeCommand("vscode.open", item.input.location.uri); +>executeCommand("vscode.open", item.input.location.uri) : Thenable +>executeCommand : (command: string, ...rest: any[]) => Thenable +>"vscode.open" : "vscode.open" +>item.input.location.uri : string +>item.input.location : { uri: string; } +>item.input : { location: { uri: string; }; } +>item : HistoryItem +>input : { location: { uri: string; }; } +>location : { uri: string; } +>uri : string + } +}); + diff --git a/tests/cases/compiler/noImplicitReturnsExclusions.ts b/tests/cases/compiler/noImplicitReturnsExclusions.ts index 61226026e5c94..380b22d11b2af 100644 --- a/tests/cases/compiler/noImplicitReturnsExclusions.ts +++ b/tests/cases/compiler/noImplicitReturnsExclusions.ts @@ -58,3 +58,39 @@ function f16(b: boolean) { // Error if (b) return 42; if (b) return; } + +declare class HistoryItem { + input: { + location: { + uri: string; + }; + }; +} + +interface Thenable { + then( + onfulfilled?: (value: T) => TResult | Thenable, + onrejected?: (reason: any) => TResult | Thenable + ): Thenable; + then( + onfulfilled?: (value: T) => TResult | Thenable, + onrejected?: (reason: any) => void + ): Thenable; +} + +export declare function executeCommand( + command: string, + ...rest: any[] +): Thenable; + +export declare function registerCommand( + command: string, + callback: (...args: any[]) => any, + thisArg?: any +): void; + +registerCommand("_references-view.showHistoryItem", async (item) => { // Error, contextual return type of Promise + if (item instanceof HistoryItem) { + return executeCommand("vscode.open", item.input.location.uri); + } +}); diff --git a/tests/cases/conformance/types/contextualTypes/asyncFunctions/contextuallyTypeAsyncFunctionReturnType.ts b/tests/cases/conformance/types/contextualTypes/asyncFunctions/contextuallyTypeAsyncFunctionReturnType.ts index b2239b9bda617..26b1ef6a86c66 100644 --- a/tests/cases/conformance/types/contextualTypes/asyncFunctions/contextuallyTypeAsyncFunctionReturnType.ts +++ b/tests/cases/conformance/types/contextualTypes/asyncFunctions/contextuallyTypeAsyncFunctionReturnType.ts @@ -22,4 +22,67 @@ async function fn4(): Promise { return await new Promise(resolve => { resolve({ key: "value" }); }); -} \ No newline at end of file +} + +declare class Context { + private _runnable; +} +type Done = (err?: any) => void; +type Func = (this: Context, done: Done) => void; +type AsyncFunc = (this: Context) => PromiseLike; + +interface TestFunction { + (fn: Func): void; + (fn: AsyncFunc): void; + (title: string, fn?: Func): void; + (title: string, fn?: AsyncFunc): void; +} + +declare const test: TestFunction; + +interface ProcessTreeNode { + pid: number; + name: string; + memory?: number; + commandLine?: string; + children: ProcessTreeNode[]; +} + +export declare function getProcessTree( + rootPid: number, + callback: (tree: ProcessTreeNode) => void +): void; + +test("windows-process-tree", async () => { + return new Promise((resolve, reject) => { + getProcessTree(123, (tree) => { + if (tree) { + resolve(); + } else { + reject(new Error("windows-process-tree")); + } + }); + }); +}); + +interface ILocalExtension { + isApplicationScoped: boolean; + publisherId: string | null; +} +type Metadata = { + updated: boolean; +}; +declare function scanMetadata( + local: ILocalExtension +): Promise; + +async function copyExtensions( + fromExtensions: ILocalExtension[] +): Promise { + const extensions: [ILocalExtension, Metadata | undefined][] = + await Promise.all( + fromExtensions + .filter((e) => !e.isApplicationScoped) + .map(async (e) => [e, await scanMetadata(e)]) + ); +} From 03c6ee4d262a5733e406251dc64599ef35ad46f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 26 Oct 2023 11:21:49 +0200 Subject: [PATCH 7/7] Add test cases from #56222 --- ...eOfYieldWithUnionInContextualReturnType.js | 74 ++++++++++++ ...eldWithUnionInContextualReturnType.symbols | 86 ++++++++++++++ ...YieldWithUnionInContextualReturnType.types | 106 ++++++++++++++++++ ...eOfYieldWithUnionInContextualReturnType.ts | 40 +++++++ 4 files changed, 306 insertions(+) create mode 100644 tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.js create mode 100644 tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.symbols create mode 100644 tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.types create mode 100644 tests/cases/compiler/typeOfYieldWithUnionInContextualReturnType.ts diff --git a/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.js b/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.js new file mode 100644 index 0000000000000..1e795fd59e5b1 --- /dev/null +++ b/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.js @@ -0,0 +1,74 @@ +//// [tests/cases/compiler/typeOfYieldWithUnionInContextualReturnType.ts] //// + +//// [typeOfYieldWithUnionInContextualReturnType.ts] +// https://github.com/microsoft/TypeScript/issues/42439 + +type SyncSequenceFactory = () => Generator; + +type AsyncSequenceFactory = () => AsyncGenerator; + +type SequenceFactory = SyncSequenceFactory | AsyncSequenceFactory + +const syncFactory: SyncSequenceFactory = function* (){ + let name = ""; + while(!name){ + name = yield "What is your name?" + } + return `That's the end of the game, ${name}` +} + +const asyncFactory: AsyncSequenceFactory = async function* (){ + let name = ""; + while(!name){ + name = yield "What is your name?" + } + return `That's the end of the game, ${name}` +} + +const looserSyncFactory: SequenceFactory = function* (){ + let name = ""; + while(!name){ + name = yield "What is your name?" + } + return `That's the end of the game, ${name}` +} + +const looserAsyncFactory: SequenceFactory = async function* (){ + let name = ""; + while(!name){ + name = yield "What is your name?" + } + return `That's the end of the game, ${name}` +} + + +//// [typeOfYieldWithUnionInContextualReturnType.js] +// https://github.com/microsoft/TypeScript/issues/42439 +const syncFactory = function* () { + let name = ""; + while (!name) { + name = yield "What is your name?"; + } + return `That's the end of the game, ${name}`; +}; +const asyncFactory = async function* () { + let name = ""; + while (!name) { + name = yield "What is your name?"; + } + return `That's the end of the game, ${name}`; +}; +const looserSyncFactory = function* () { + let name = ""; + while (!name) { + name = yield "What is your name?"; + } + return `That's the end of the game, ${name}`; +}; +const looserAsyncFactory = async function* () { + let name = ""; + while (!name) { + name = yield "What is your name?"; + } + return `That's the end of the game, ${name}`; +}; diff --git a/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.symbols b/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.symbols new file mode 100644 index 0000000000000..5bfb0cb71fe9d --- /dev/null +++ b/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.symbols @@ -0,0 +1,86 @@ +//// [tests/cases/compiler/typeOfYieldWithUnionInContextualReturnType.ts] //// + +=== typeOfYieldWithUnionInContextualReturnType.ts === +// https://github.com/microsoft/TypeScript/issues/42439 + +type SyncSequenceFactory = () => Generator; +>SyncSequenceFactory : Symbol(SyncSequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 0, 0)) +>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) + +type AsyncSequenceFactory = () => AsyncGenerator; +>AsyncSequenceFactory : Symbol(AsyncSequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 2, 67)) +>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --)) + +type SequenceFactory = SyncSequenceFactory | AsyncSequenceFactory +>SequenceFactory : Symbol(SequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 4, 73)) +>SyncSequenceFactory : Symbol(SyncSequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 0, 0)) +>AsyncSequenceFactory : Symbol(AsyncSequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 2, 67)) + +const syncFactory: SyncSequenceFactory = function* (){ +>syncFactory : Symbol(syncFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 8, 5)) +>SyncSequenceFactory : Symbol(SyncSequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 0, 0)) + + let name = ""; +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 9, 5)) + + while(!name){ +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 9, 5)) + + name = yield "What is your name?" +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 9, 5)) + } + return `That's the end of the game, ${name}` +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 9, 5)) +} + +const asyncFactory: AsyncSequenceFactory = async function* (){ +>asyncFactory : Symbol(asyncFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 16, 5)) +>AsyncSequenceFactory : Symbol(AsyncSequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 2, 67)) + + let name = ""; +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 17, 5)) + + while(!name){ +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 17, 5)) + + name = yield "What is your name?" +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 17, 5)) + } + return `That's the end of the game, ${name}` +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 17, 5)) +} + +const looserSyncFactory: SequenceFactory = function* (){ +>looserSyncFactory : Symbol(looserSyncFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 24, 5)) +>SequenceFactory : Symbol(SequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 4, 73)) + + let name = ""; +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 25, 5)) + + while(!name){ +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 25, 5)) + + name = yield "What is your name?" +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 25, 5)) + } + return `That's the end of the game, ${name}` +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 25, 5)) +} + +const looserAsyncFactory: SequenceFactory = async function* (){ +>looserAsyncFactory : Symbol(looserAsyncFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 32, 5)) +>SequenceFactory : Symbol(SequenceFactory, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 4, 73)) + + let name = ""; +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 33, 5)) + + while(!name){ +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 33, 5)) + + name = yield "What is your name?" +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 33, 5)) + } + return `That's the end of the game, ${name}` +>name : Symbol(name, Decl(typeOfYieldWithUnionInContextualReturnType.ts, 33, 5)) +} + diff --git a/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.types b/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.types new file mode 100644 index 0000000000000..d6e02113f1a8e --- /dev/null +++ b/tests/baselines/reference/typeOfYieldWithUnionInContextualReturnType.types @@ -0,0 +1,106 @@ +//// [tests/cases/compiler/typeOfYieldWithUnionInContextualReturnType.ts] //// + +=== typeOfYieldWithUnionInContextualReturnType.ts === +// https://github.com/microsoft/TypeScript/issues/42439 + +type SyncSequenceFactory = () => Generator; +>SyncSequenceFactory : () => Generator + +type AsyncSequenceFactory = () => AsyncGenerator; +>AsyncSequenceFactory : () => AsyncGenerator + +type SequenceFactory = SyncSequenceFactory | AsyncSequenceFactory +>SequenceFactory : SyncSequenceFactory | AsyncSequenceFactory + +const syncFactory: SyncSequenceFactory = function* (){ +>syncFactory : SyncSequenceFactory +>function* (){ let name = ""; while(!name){ name = yield "What is your name?" } return `That's the end of the game, ${name}`} : () => Generator + + let name = ""; +>name : string +>"" : "" + + while(!name){ +>!name : boolean +>name : string + + name = yield "What is your name?" +>name = yield "What is your name?" : string +>name : string +>yield "What is your name?" : string +>"What is your name?" : "What is your name?" + } + return `That's the end of the game, ${name}` +>`That's the end of the game, ${name}` : string +>name : string +} + +const asyncFactory: AsyncSequenceFactory = async function* (){ +>asyncFactory : AsyncSequenceFactory +>async function* (){ let name = ""; while(!name){ name = yield "What is your name?" } return `That's the end of the game, ${name}`} : () => AsyncGenerator + + let name = ""; +>name : string +>"" : "" + + while(!name){ +>!name : boolean +>name : string + + name = yield "What is your name?" +>name = yield "What is your name?" : string +>name : string +>yield "What is your name?" : string +>"What is your name?" : "What is your name?" + } + return `That's the end of the game, ${name}` +>`That's the end of the game, ${name}` : string +>name : string +} + +const looserSyncFactory: SequenceFactory = function* (){ +>looserSyncFactory : SequenceFactory +>function* (){ let name = ""; while(!name){ name = yield "What is your name?" } return `That's the end of the game, ${name}`} : () => Generator + + let name = ""; +>name : string +>"" : "" + + while(!name){ +>!name : boolean +>name : string + + name = yield "What is your name?" +>name = yield "What is your name?" : string +>name : string +>yield "What is your name?" : string +>"What is your name?" : "What is your name?" + } + return `That's the end of the game, ${name}` +>`That's the end of the game, ${name}` : string +>name : string +} + +const looserAsyncFactory: SequenceFactory = async function* (){ +>looserAsyncFactory : SequenceFactory +>async function* (){ let name = ""; while(!name){ name = yield "What is your name?" } return `That's the end of the game, ${name}`} : () => AsyncGenerator + + let name = ""; +>name : string +>"" : "" + + while(!name){ +>!name : boolean +>name : string + + name = yield "What is your name?" +>name = yield "What is your name?" : string +>name : string +>yield "What is your name?" : string +>"What is your name?" : "What is your name?" + } + return `That's the end of the game, ${name}` +>`That's the end of the game, ${name}` : string +>name : string +} + diff --git a/tests/cases/compiler/typeOfYieldWithUnionInContextualReturnType.ts b/tests/cases/compiler/typeOfYieldWithUnionInContextualReturnType.ts new file mode 100644 index 0000000000000..567694b0b2bba --- /dev/null +++ b/tests/cases/compiler/typeOfYieldWithUnionInContextualReturnType.ts @@ -0,0 +1,40 @@ +// @target: esnext +// https://github.com/microsoft/TypeScript/issues/42439 + +type SyncSequenceFactory = () => Generator; + +type AsyncSequenceFactory = () => AsyncGenerator; + +type SequenceFactory = SyncSequenceFactory | AsyncSequenceFactory + +const syncFactory: SyncSequenceFactory = function* (){ + let name = ""; + while(!name){ + name = yield "What is your name?" + } + return `That's the end of the game, ${name}` +} + +const asyncFactory: AsyncSequenceFactory = async function* (){ + let name = ""; + while(!name){ + name = yield "What is your name?" + } + return `That's the end of the game, ${name}` +} + +const looserSyncFactory: SequenceFactory = function* (){ + let name = ""; + while(!name){ + name = yield "What is your name?" + } + return `That's the end of the game, ${name}` +} + +const looserAsyncFactory: SequenceFactory = async function* (){ + let name = ""; + while(!name){ + name = yield "What is your name?" + } + return `That's the end of the game, ${name}` +}