Skip to content

Commit 28e8c4f

Browse files
author
Andy
authored
Factor out a getYieldedTypeOfYieldExpression helper (#22416)
1 parent 87d88e2 commit 28e8c4f

File tree

1 file changed

+46
-68
lines changed

1 file changed

+46
-68
lines changed

src/compiler/checker.ts

Lines changed: 46 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -18523,27 +18523,25 @@ namespace ts {
1852318523

1852418524
function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode): Type[] {
1852518525
const aggregatedTypes: Type[] = [];
18526-
const functionFlags = getFunctionFlags(func);
18526+
const isAsync = (getFunctionFlags(func) & FunctionFlags.Async) !== 0;
1852718527
forEachYieldExpression(<Block>func.body, yieldExpression => {
18528-
const expr = yieldExpression.expression;
18529-
if (expr) {
18530-
let type = checkExpressionCached(expr, checkMode);
18531-
if (yieldExpression.asteriskToken) {
18532-
// A yield* expression effectively yields everything that its operand yields
18533-
type = checkIteratedTypeOrElementType(type, yieldExpression.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
18534-
}
18535-
if (functionFlags & FunctionFlags.Async) {
18536-
type = checkAwaitedType(type, expr, yieldExpression.asteriskToken
18537-
? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member
18538-
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
18539-
}
18540-
pushIfUnique(aggregatedTypes, type);
18528+
if (yieldExpression.expression) { // TODO: GH#22297
18529+
pushIfUnique(aggregatedTypes, getYieldedTypeOfYieldExpression(yieldExpression, isAsync, checkMode));
1854118530
}
1854218531
});
18543-
1854418532
return aggregatedTypes;
1854518533
}
1854618534

18535+
function getYieldedTypeOfYieldExpression(node: YieldExpression, isAsync: boolean, checkMode?: CheckMode): Type {
18536+
const errorNode = node.expression || node;
18537+
const expressionType = node.expression ? checkExpressionCached(node.expression, checkMode) : undefinedWideningType;
18538+
// A `yield*` expression effectively yields everything that its operand yields
18539+
const yieldedType = node.asteriskToken ? checkIteratedTypeOrElementType(expressionType, errorNode, /*allowStringInput*/ false, isAsync) : expressionType;
18540+
return !isAsync ? yieldedType : getAwaitedType(yieldedType, errorNode, node.asteriskToken
18541+
? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member
18542+
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
18543+
}
18544+
1854718545
function isExhaustiveSwitchStatement(node: SwitchStatement): boolean {
1854818546
if (!node.possiblyExhaustive) {
1854918547
return false;
@@ -19499,62 +19497,42 @@ namespace ts {
1949919497
}
1950019498
}
1950119499

19502-
if (node.expression) {
19503-
const func = getContainingFunction(node);
19504-
// If the user's code is syntactically correct, the func should always have a star. After all,
19505-
// we are in a yield context.
19506-
const functionFlags = func && getFunctionFlags(func);
19507-
if (node.asteriskToken) {
19508-
// Async generator functions prior to ESNext require the __await, __asyncDelegator,
19509-
// and __asyncValues helpers
19510-
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator &&
19511-
languageVersion < ScriptTarget.ESNext) {
19512-
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes);
19513-
}
19514-
19515-
// Generator functions prior to ES2015 require the __values helper
19516-
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Generator &&
19517-
languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
19518-
checkExternalEmitHelpers(node, ExternalEmitHelpers.Values);
19519-
}
19520-
}
19521-
19522-
if (functionFlags & FunctionFlags.Generator) {
19523-
const expressionType = checkExpressionCached(node.expression);
19524-
let expressionElementType: Type;
19525-
const nodeIsYieldStar = !!node.asteriskToken;
19526-
if (nodeIsYieldStar) {
19527-
expressionElementType = checkIteratedTypeOrElementType(expressionType, node.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
19528-
}
19529-
19530-
// There is no point in doing an assignability check if the function
19531-
// has no explicit return type because the return type is directly computed
19532-
// from the yield expressions.
19533-
const returnType = getEffectiveReturnTypeNode(func);
19534-
if (returnType) {
19535-
const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(returnType), (functionFlags & FunctionFlags.Async) !== 0) || anyType;
19536-
if (nodeIsYieldStar) {
19537-
checkTypeAssignableTo(
19538-
functionFlags & FunctionFlags.Async
19539-
? getAwaitedType(expressionElementType, node.expression, Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)
19540-
: expressionElementType,
19541-
signatureElementType,
19542-
node.expression,
19543-
/*headMessage*/ undefined);
19544-
}
19545-
else {
19546-
checkTypeAssignableTo(
19547-
functionFlags & FunctionFlags.Async
19548-
? getAwaitedType(expressionType, node.expression, Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)
19549-
: expressionType,
19550-
signatureElementType,
19551-
node.expression,
19552-
/*headMessage*/ undefined);
19553-
}
19554-
}
19500+
const func = getContainingFunction(node);
19501+
const functionFlags = func ? getFunctionFlags(func) : FunctionFlags.Normal;
19502+
19503+
if (!(functionFlags & FunctionFlags.Generator)) {
19504+
// If the user's code is syntactically correct, the func should always have a star. After all, we are in a yield context.
19505+
return anyType;
19506+
}
19507+
19508+
if (node.asteriskToken) {
19509+
// Async generator functions prior to ESNext require the __await, __asyncDelegator,
19510+
// and __asyncValues helpers
19511+
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator &&
19512+
languageVersion < ScriptTarget.ESNext) {
19513+
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes);
19514+
}
19515+
19516+
// Generator functions prior to ES2015 require the __values helper
19517+
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Generator &&
19518+
languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
19519+
checkExternalEmitHelpers(node, ExternalEmitHelpers.Values);
1955519520
}
1955619521
}
1955719522

19523+
if (!node.expression) return anyType; // TODO: GH#22297
19524+
19525+
const isAsync = (functionFlags & FunctionFlags.Async) !== 0;
19526+
const yieldedType = getYieldedTypeOfYieldExpression(node, isAsync);
19527+
// There is no point in doing an assignability check if the function
19528+
// has no explicit return type because the return type is directly computed
19529+
// from the yield expressions.
19530+
const returnType = getEffectiveReturnTypeNode(func);
19531+
if (returnType) {
19532+
const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(returnType), isAsync) || anyType;
19533+
checkTypeAssignableTo(yieldedType, signatureElementType, node.expression || node, /*headMessage*/ undefined);
19534+
}
19535+
1955819536
// Both yield and yield* expressions have type 'any'
1955919537
return anyType;
1956019538
}

0 commit comments

Comments
 (0)