Skip to content

Error on too many parameters for iterator method #60321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
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
51 changes: 28 additions & 23 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ import {
EnumMember,
EnumType,
equateValues,
ErrorOutputContainer,
escapeLeadingUnderscores,
escapeString,
EvaluatorResult,
Expand Down Expand Up @@ -20608,7 +20609,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
expr: Expression | undefined,
headMessage: DiagnosticMessage | undefined,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
): boolean {
if (isTypeRelatedTo(source, target, relation)) return true;
if (!errorNode || !elaborateError(expr, source, target, relation, headMessage, containingMessageChain, errorOutputContainer)) {
Expand All @@ -20628,7 +20629,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
relation: Map<string, RelationComparisonResult>,
headMessage: DiagnosticMessage | undefined,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
): boolean {
if (!node || isOrHasGenericConditional(target)) return false;
if (
Expand Down Expand Up @@ -20672,7 +20673,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
relation: Map<string, RelationComparisonResult>,
headMessage: DiagnosticMessage | undefined,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
): boolean {
const callSignatures = getSignaturesOfType(source, SignatureKind.Call);
const constructSignatures = getSignaturesOfType(source, SignatureKind.Construct);
Expand Down Expand Up @@ -20705,7 +20706,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
target: Type,
relation: Map<string, RelationComparisonResult>,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
): boolean {
// Don't elaborate blocks
if (isBlock(node.body)) {
Expand Down Expand Up @@ -20796,7 +20797,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
target: Type,
relation: Map<string, RelationComparisonResult>,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
) {
// Assignability failure - check each prop individually, and if that fails, fall back on the bad error span
let reportedError = false;
Expand Down Expand Up @@ -20876,7 +20877,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
target: Type,
relation: Map<string, RelationComparisonResult>,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
) {
const tupleOrArrayLikeTargetParts = filterType(target, isArrayOrTupleLikeType);
const nonTupleOrArrayLikeTargetParts = filterType(target, t => !isArrayOrTupleLikeType(t));
Expand Down Expand Up @@ -20978,7 +20979,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
target: Type,
relation: Map<string, RelationComparisonResult>,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
) {
let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation, containingMessageChain, errorOutputContainer);
let invalidTextDiagnostic: DiagnosticMessage | undefined;
Expand Down Expand Up @@ -21092,7 +21093,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
target: Type,
relation: Map<string, RelationComparisonResult>,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
) {
if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false;
if (isTupleLikeType(source)) {
Expand Down Expand Up @@ -21139,7 +21140,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
target: Type,
relation: Map<string, RelationComparisonResult>,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined,
errorOutputContainer: ErrorOutputContainer | undefined,
) {
if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false;
return elaborateElementwise(generateObjectLiteralElements(node), source, target, relation, containingMessageChain, errorOutputContainer);
Expand Down Expand Up @@ -21637,7 +21638,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
errorNode: Node | undefined,
headMessage?: DiagnosticMessage,
containingMessageChain?: () => DiagnosticMessageChain | undefined,
errorOutputContainer?: { errors?: Diagnostic[]; skipLogging?: boolean; },
errorOutputContainer?: ErrorOutputContainer,
): boolean {
let errorInfo: DiagnosticMessageChain | undefined;
let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined;
Expand Down Expand Up @@ -35186,7 +35187,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
checkMode: CheckMode,
reportErrors: boolean,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; },
errorOutputContainer: ErrorOutputContainer,
) {
// Stateless function components can have maximum of three arguments: "props", "context", and "updater".
// However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props,
Expand Down Expand Up @@ -35302,7 +35303,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
inferenceContext: InferenceContext | undefined,
): readonly Diagnostic[] | undefined {
const errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } = { errors: undefined, skipLogging: true };
const errorOutputContainer: ErrorOutputContainer = { errors: undefined, skipLogging: true };
if (isJsxCallLike(node)) {
if (!checkApplicableSignatureForJsxCallLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer)) {
Debug.assert(!reportErrors || !!errorOutputContainer.errors, "jsx should have errors when reporting errors");
Expand Down Expand Up @@ -44934,7 +44935,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

if (!(type.flags & TypeFlags.Union)) {
const errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined = errorNode ? { errors: undefined } : undefined;
const errorOutputContainer: ErrorOutputContainer | undefined = errorNode ? { errors: undefined, skipLogging: true } : undefined;
const iterationTypes = getIterationTypesOfIterableWorker(type, use, errorNode, errorOutputContainer);
if (iterationTypes === noIterationTypes) {
if (errorNode) {
Expand All @@ -44959,7 +44960,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

let allIterationTypes: IterationTypes[] | undefined;
for (const constituent of (type as UnionType).types) {
const errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined = errorNode ? { errors: undefined } : undefined;
const errorOutputContainer: ErrorOutputContainer | undefined = errorNode ? { errors: undefined } : undefined;
const iterationTypes = getIterationTypesOfIterableWorker(constituent, use, errorNode, errorOutputContainer);
if (iterationTypes === noIterationTypes) {
if (errorNode) {
Expand Down Expand Up @@ -45010,7 +45011,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* NOTE: You probably don't want to call this directly and should be calling
* `getIterationTypesOfIterable` instead.
*/
function getIterationTypesOfIterableWorker(type: Type, use: IterationUse, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined) {
function getIterationTypesOfIterableWorker(type: Type, use: IterationUse, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined) {
if (isTypeAny(type)) {
return anyIterationTypes;
}
Expand Down Expand Up @@ -45152,19 +45153,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* NOTE: You probably don't want to call this directly and should be calling
* `getIterationTypesOfIterable` instead.
*/
function getIterationTypesOfIterableSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, noCache: boolean) {
function getIterationTypesOfIterableSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined, noCache: boolean) {
const method = getPropertyOfType(type, getPropertyNameForKnownSymbolName(resolver.iteratorSymbolName));
const methodType = method && !(method.flags & SymbolFlags.Optional) ? getTypeOfSymbol(method) : undefined;
if (isTypeAny(methodType)) {
return noCache ? anyIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, anyIterationTypes);
}

const signatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : undefined;
if (!some(signatures)) {
const allSignatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : undefined;
const validSignatures = filter(allSignatures, sig => getMinArgumentCount(sig) === 0);
if (!some(validSignatures)) {
if (errorNode && some(allSignatures)) {
checkTypeAssignableTo(type, resolver.getGlobalIterableType(/*reportErrors*/ true), errorNode, /*headMessage*/ undefined, /*containingMessageChain*/ undefined, errorOutputContainer);
}
return noCache ? noIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes);
}

const iteratorType = getIntersectionType(map(signatures, getReturnTypeOfSignature));
const iteratorType = getIntersectionType(map(validSignatures, getReturnTypeOfSignature));
const iterationTypes = getIterationTypesOfIteratorWorker(iteratorType, resolver, errorNode, errorOutputContainer, noCache) ?? noIterationTypes;
return noCache ? iterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, iterationTypes);
}
Expand Down Expand Up @@ -45193,7 +45198,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes`
* record is returned. Otherwise, `undefined` is returned.
*/
function getIterationTypesOfIterator(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined) {
function getIterationTypesOfIterator(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined) {
return getIterationTypesOfIteratorWorker(type, resolver, errorNode, errorOutputContainer, /*noCache*/ false);
}

Expand All @@ -45206,7 +45211,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* NOTE: You probably don't want to call this directly and should be calling
* `getIterationTypesOfIterator` instead.
*/
function getIterationTypesOfIteratorWorker(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, noCache: boolean) {
function getIterationTypesOfIteratorWorker(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined, noCache: boolean) {
if (isTypeAny(type)) {
return anyIterationTypes;
}
Expand Down Expand Up @@ -45348,7 +45353,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes`
* record is returned. Otherwise, we return `undefined`.
*/
function getIterationTypesOfMethod(type: Type, resolver: IterationTypesResolver, methodName: "next" | "return" | "throw", errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined): IterationTypes | undefined {
function getIterationTypesOfMethod(type: Type, resolver: IterationTypesResolver, methodName: "next" | "return" | "throw", errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined): IterationTypes | undefined {
const method = getPropertyOfType(type, methodName as __String);

// Ignore 'return' or 'throw' if they are missing.
Expand Down Expand Up @@ -45468,7 +45473,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* NOTE: You probably don't want to call this directly and should be calling
* `getIterationTypesOfIterator` instead.
*/
function getIterationTypesOfIteratorSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, noCache: boolean) {
function getIterationTypesOfIteratorSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: ErrorOutputContainer | undefined, noCache: boolean) {
const iterationTypes = combineIterationTypes([
getIterationTypesOfMethod(type, resolver, "next", errorNode, errorOutputContainer),
getIterationTypesOfMethod(type, resolver, "return", errorNode, errorOutputContainer),
Expand Down
6 changes: 6 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9981,6 +9981,12 @@ export interface TextChangeRange {
newLength: number;
}

/** @internal */
export interface ErrorOutputContainer {
errors?: Diagnostic[];
skipLogging?: boolean;
}

/** @internal */
export interface DiagnosticCollection {
// Adds a diagnostic to this diagnostic collection.
Expand Down
32 changes: 32 additions & 0 deletions tests/baselines/reference/asyncIteratorExtraParameters.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
asyncIteratorExtraParameters.ts(11,27): error TS2504: Type '{ [Symbol.asyncIterator](_: number): AsyncGenerator<number, void, unknown>; }' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.
asyncIteratorExtraParameters.ts(13,12): error TS2504: Type '{ [Symbol.asyncIterator](_: number): AsyncGenerator<number, void, unknown>; }' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.


==== asyncIteratorExtraParameters.ts (2 errors) ====
// https://github.com/microsoft/TypeScript/issues/57130
const iter = {
async *[Symbol.asyncIterator](_: number) {
yield 0;
}
};

declare function g(...args: any): any;

async function* f() {
for await (const _ of iter);
~~~~
!!! error TS2504: Type '{ [Symbol.asyncIterator](_: number): AsyncGenerator<number, void, unknown>; }' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.
!!! related TS2322 asyncIteratorExtraParameters.ts:11:27: Type '{ [Symbol.asyncIterator](_: number): AsyncGenerator<number, void, unknown>; }' is not assignable to type 'AsyncIterable<T, TReturn, TNext>'.
Types of property '[Symbol.asyncIterator]' are incompatible.
Type '(_: number) => AsyncGenerator<number, void, unknown>' is not assignable to type '() => AsyncIterator<T, TReturn, TNext>'.
Target signature provides too few arguments. Expected 1 or more, but got 0.

yield* iter;
~~~~
!!! error TS2504: Type '{ [Symbol.asyncIterator](_: number): AsyncGenerator<number, void, unknown>; }' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.
!!! related TS2322 asyncIteratorExtraParameters.ts:13:12: Type '{ [Symbol.asyncIterator](_: number): AsyncGenerator<number, void, unknown>; }' is not assignable to type 'AsyncIterable<T, TReturn, TNext>'.
Types of property '[Symbol.asyncIterator]' are incompatible.
Type '(_: number) => AsyncGenerator<number, void, unknown>' is not assignable to type '() => AsyncIterator<T, TReturn, TNext>'.
Target signature provides too few arguments. Expected 1 or more, but got 0.
}

Loading