Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 46 additions & 68 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18523,27 +18523,25 @@ namespace ts {

function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode): Type[] {
const aggregatedTypes: Type[] = [];
const functionFlags = getFunctionFlags(func);
const isAsync = (getFunctionFlags(func) & FunctionFlags.Async) !== 0;
forEachYieldExpression(<Block>func.body, yieldExpression => {
const expr = yieldExpression.expression;
if (expr) {
let type = checkExpressionCached(expr, checkMode);
if (yieldExpression.asteriskToken) {
// A yield* expression effectively yields everything that its operand yields
type = checkIteratedTypeOrElementType(type, yieldExpression.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
}
if (functionFlags & FunctionFlags.Async) {
type = checkAwaitedType(type, expr, yieldExpression.asteriskToken
? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
}
pushIfUnique(aggregatedTypes, type);
if (yieldExpression.expression) { // TODO: GH#22297
pushIfUnique(aggregatedTypes, getYieldedTypeOfYieldExpression(yieldExpression, isAsync, checkMode));
}
});

return aggregatedTypes;
}

function getYieldedTypeOfYieldExpression(node: YieldExpression, isAsync: boolean, checkMode?: CheckMode): Type {
const errorNode = node.expression || node;
const expressionType = node.expression ? checkExpressionCached(node.expression, checkMode) : undefinedWideningType;
// A `yield*` expression effectively yields everything that its operand yields
const yieldedType = node.asteriskToken ? checkIteratedTypeOrElementType(expressionType, errorNode, /*allowStringInput*/ false, isAsync) : expressionType;
return !isAsync ? yieldedType : getAwaitedType(yieldedType, errorNode, node.asteriskToken
? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
}

function isExhaustiveSwitchStatement(node: SwitchStatement): boolean {
if (!node.possiblyExhaustive) {
return false;
Expand Down Expand Up @@ -19499,62 +19497,42 @@ namespace ts {
}
}

if (node.expression) {
const func = getContainingFunction(node);
// If the user's code is syntactically correct, the func should always have a star. After all,
// we are in a yield context.
const functionFlags = func && getFunctionFlags(func);
if (node.asteriskToken) {
// Async generator functions prior to ESNext require the __await, __asyncDelegator,
// and __asyncValues helpers
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator &&
languageVersion < ScriptTarget.ESNext) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes);
}

// Generator functions prior to ES2015 require the __values helper
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Generator &&
languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Values);
}
}

if (functionFlags & FunctionFlags.Generator) {
const expressionType = checkExpressionCached(node.expression);
let expressionElementType: Type;
const nodeIsYieldStar = !!node.asteriskToken;
if (nodeIsYieldStar) {
expressionElementType = checkIteratedTypeOrElementType(expressionType, node.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
}

// 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 = getEffectiveReturnTypeNode(func);
if (returnType) {
const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(returnType), (functionFlags & FunctionFlags.Async) !== 0) || anyType;
if (nodeIsYieldStar) {
checkTypeAssignableTo(
functionFlags & FunctionFlags.Async
? 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)
: expressionElementType,
signatureElementType,
node.expression,
/*headMessage*/ undefined);
}
else {
checkTypeAssignableTo(
functionFlags & FunctionFlags.Async
? 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)
: expressionType,
signatureElementType,
node.expression,
/*headMessage*/ undefined);
}
}
const func = getContainingFunction(node);
const functionFlags = func ? getFunctionFlags(func) : FunctionFlags.Normal;

if (!(functionFlags & FunctionFlags.Generator)) {
// If the user's code is syntactically correct, the func should always have a star. After all, we are in a yield context.
return anyType;
}

if (node.asteriskToken) {
// Async generator functions prior to ESNext require the __await, __asyncDelegator,
// and __asyncValues helpers
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator &&
languageVersion < ScriptTarget.ESNext) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes);
}

// Generator functions prior to ES2015 require the __values helper
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Generator &&
languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Values);
}
}

if (!node.expression) return anyType; // TODO: GH#22297

const isAsync = (functionFlags & FunctionFlags.Async) !== 0;
const yieldedType = getYieldedTypeOfYieldExpression(node, isAsync);
// 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 = getEffectiveReturnTypeNode(func);
if (returnType) {
const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(returnType), isAsync) || anyType;
checkTypeAssignableTo(yieldedType, signatureElementType, node.expression || node, /*headMessage*/ undefined);
}

// Both yield and yield* expressions have type 'any'
return anyType;
}
Expand Down