diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3cd8418bde007..221caf82321ae 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -932,6 +932,19 @@ namespace ts { addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message)); } + function errorAndMaybeSuggestAwait( + location: Node, + maybeMissingAwait: boolean, + message: DiagnosticMessage, + arg0?: string | number | undefined, arg1?: string | number | undefined, arg2?: string | number | undefined, arg3?: string | number | undefined): Diagnostic { + const diagnostic = error(location, message, arg0, arg1, arg2, arg3); + if (maybeMissingAwait) { + const related = createDiagnosticForNode(location, Diagnostics.Did_you_forget_to_use_await); + addRelatedInfo(diagnostic, related); + } + return diagnostic; + } + function createSymbol(flags: SymbolFlags, name: __String, checkFlags?: CheckFlags) { symbolCount++; const symbol = (new Symbol(flags | SymbolFlags.Transient, name)); @@ -21426,6 +21439,7 @@ namespace ts { const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage, containingMessageChain, errorOutputContainer)) { Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors"); + maybeAddMissingAwaitInfo(arg, checkArgType, paramType); return errorOutputContainer.errors || []; } } @@ -21435,10 +21449,24 @@ namespace ts { const errorNode = reportErrors ? argCount < args.length ? args[argCount] : node : undefined; if (!checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage, /*containingMessageChain*/ undefined, errorOutputContainer)) { Debug.assert(!reportErrors || !!errorOutputContainer.errors, "rest parameter should have errors when reporting errors"); + maybeAddMissingAwaitInfo(errorNode, spreadType, restType); return errorOutputContainer.errors || []; } } return undefined; + + function maybeAddMissingAwaitInfo(errorNode: Node | undefined, source: Type, target: Type) { + if (errorNode && reportErrors && errorOutputContainer.errors && errorOutputContainer.errors.length) { + // Bail if target is Promise-like---something else is wrong + if (getAwaitedTypeOfPromise(target)) { + return; + } + const awaitedTypeOfSource = getAwaitedTypeOfPromise(source); + if (awaitedTypeOfSource && isTypeRelatedTo(awaitedTypeOfSource, target, relation)) { + addRelatedInfo(errorOutputContainer.errors[0], createDiagnosticForNode(errorNode, Diagnostics.Did_you_forget_to_use_await)); + } + } + } } /** @@ -22340,9 +22368,11 @@ namespace ts { return true; } - function invocationErrorDetails(apparentType: Type, kind: SignatureKind): DiagnosticMessageChain { + function invocationErrorDetails(apparentType: Type, kind: SignatureKind): { messageChain: DiagnosticMessageChain, relatedMessage: DiagnosticMessage | undefined } { let errorInfo: DiagnosticMessageChain | undefined; const isCall = kind === SignatureKind.Call; + const awaitedType = getAwaitedType(apparentType); + const maybeMissingAwait = awaitedType && getSignaturesOfType(awaitedType, kind).length > 0; if (apparentType.flags & TypeFlags.Union) { const types = (apparentType as UnionType).types; let hasSignatures = false; @@ -22407,15 +22437,20 @@ namespace ts { typeToString(apparentType) ); } - return chainDiagnosticMessages( - errorInfo, - isCall ? - Diagnostics.This_expression_is_not_callable : - Diagnostics.This_expression_is_not_constructable - ); + return { + messageChain: chainDiagnosticMessages( + errorInfo, + isCall ? Diagnostics.This_expression_is_not_callable : Diagnostics.This_expression_is_not_constructable + ), + relatedMessage: maybeMissingAwait ? Diagnostics.Did_you_forget_to_use_await : undefined, + }; } function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) { - const diagnostic = createDiagnosticForNodeFromMessageChain(errorTarget, invocationErrorDetails(apparentType, kind)); + const { messageChain, relatedMessage: relatedInfo } = invocationErrorDetails(apparentType, kind); + const diagnostic = createDiagnosticForNodeFromMessageChain(errorTarget, messageChain); + if (relatedInfo) { + addRelatedInfo(diagnostic, createDiagnosticForNode(errorTarget, relatedInfo)); + } if (isCallExpression(errorTarget.parent)) { const { start, length } = getDiagnosticSpanForCallNode(errorTarget.parent, /* doNotIncludeArguments */ true); diagnostic.start = start; @@ -22515,9 +22550,12 @@ namespace ts { const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node); if (!callSignatures.length) { - let errorInfo = invocationErrorDetails(apparentType, SignatureKind.Call); - errorInfo = chainDiagnosticMessages(errorInfo, headMessage); - const diag = createDiagnosticForNodeFromMessageChain(node.expression, errorInfo); + const errorDetails = invocationErrorDetails(apparentType, SignatureKind.Call); + const messageChain = chainDiagnosticMessages(errorDetails.messageChain, headMessage); + const diag = createDiagnosticForNodeFromMessageChain(node.expression, messageChain); + if (errorDetails.relatedMessage) { + addRelatedInfo(diag, createDiagnosticForNode(node.expression, errorDetails.relatedMessage)); + } diagnostics.add(diag); invocationErrorRecovery(apparentType, SignatureKind.Call, diag); return resolveErrorCall(node); @@ -23677,7 +23715,11 @@ namespace ts { function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage): boolean { if (!isTypeAssignableTo(type, numberOrBigIntType)) { - error(operand, diagnostic); + const awaitedType = getAwaitedType(type); + errorAndMaybeSuggestAwait( + operand, + !!awaitedType && isTypeAssignableTo(awaitedType, numberOrBigIntType), + diagnostic); return false; } return true; @@ -24295,7 +24337,7 @@ namespace ts { ) { resultType = numberType; } - // At least one is assignable to bigint, so both should be only assignable to bigint + // At least one is assignable to bigint, so check that both are else if (isTypeAssignableToKind(leftType, TypeFlags.BigIntLike) && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike)) { switch (operator) { case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: @@ -24304,8 +24346,9 @@ namespace ts { } resultType = bigintType; } + // Exactly one of leftType/rightType is assignable to bigint else { - reportOperatorError(); + reportOperatorError((awaitedLeft, awaitedRight) => isTypeAssignableToKind(awaitedLeft, TypeFlags.BigIntLike) && isTypeAssignableToKind(awaitedRight, TypeFlags.BigIntLike)); resultType = errorType; } if (leftOk && rightOk) { @@ -24350,7 +24393,14 @@ namespace ts { } if (!resultType) { - reportOperatorError(); + // Types that have a reasonably good chance of being a valid operand type. + // If both types have an awaited type of one of these, we’ll assume the user + // might be missing an await without doing an exhaustive check that inserting + // await(s) will actually be a completely valid binary expression. + const closeEnoughKind = TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.AnyOrUnknown; + reportOperatorError((awaitedLeft, awaitedRight) => + isTypeAssignableToKind(awaitedLeft, closeEnoughKind) && + isTypeAssignableToKind(awaitedRight, closeEnoughKind)); return anyType; } @@ -24365,21 +24415,18 @@ namespace ts { if (checkForDisallowedESSymbolOperand(operator)) { leftType = getBaseTypeOfLiteralType(checkNonNullType(leftType, left)); rightType = getBaseTypeOfLiteralType(checkNonNullType(rightType, right)); - if (!(isTypeComparableTo(leftType, rightType) || isTypeComparableTo(rightType, leftType) || - (isTypeAssignableTo(leftType, numberOrBigIntType) && isTypeAssignableTo(rightType, numberOrBigIntType)) - )) { - reportOperatorError(); - } + reportOperatorErrorUnless((left, right) => + isTypeComparableTo(left, right) || isTypeComparableTo(right, left) || ( + isTypeAssignableTo(left, numberOrBigIntType) && isTypeAssignableTo(right, numberOrBigIntType))); } return booleanType; case SyntaxKind.EqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: - if (!isTypeEqualityComparableTo(leftType, rightType) && !isTypeEqualityComparableTo(rightType, leftType)) { - reportOperatorError(); - } + reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left)); return booleanType; + case SyntaxKind.InstanceOfKeyword: return checkInstanceOfExpression(left, right, leftType, rightType); case SyntaxKind.InKeyword: @@ -24506,12 +24553,33 @@ namespace ts { } } - function reportOperatorError() { - const [leftStr, rightStr] = getTypeNamesForErrorDisplay(leftType, rightType); + /** + * Returns true if an error is reported + */ + function reportOperatorErrorUnless(typesAreCompatible: (left: Type, right: Type) => boolean): boolean { + if (!typesAreCompatible(leftType, rightType)) { + reportOperatorError(typesAreCompatible); + return true; + } + return false; + } + + function reportOperatorError(awaitedTypesAreCompatible?: (left: Type, right: Type) => boolean) { + let wouldWorkWithAwait = false; const errNode = errorNode || operatorToken; - if (!tryGiveBetterPrimaryError(errNode, leftStr, rightStr)) { - error( + const [leftStr, rightStr] = getTypeNamesForErrorDisplay(leftType, rightType); + if (awaitedTypesAreCompatible) { + const awaitedLeftType = getAwaitedType(leftType); + const awaitedRightType = getAwaitedType(rightType); + wouldWorkWithAwait = !(awaitedLeftType === leftType && awaitedRightType === rightType) + && !!(awaitedLeftType && awaitedRightType) + && awaitedTypesAreCompatible(awaitedLeftType, awaitedRightType); + } + + if (!tryGiveBetterPrimaryError(errNode, wouldWorkWithAwait, leftStr, rightStr)) { + errorAndMaybeSuggestAwait( errNode, + wouldWorkWithAwait, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2, tokenToString(operatorToken.kind), leftStr, @@ -24520,15 +24588,26 @@ namespace ts { } } - function tryGiveBetterPrimaryError(errNode: Node, leftStr: string, rightStr: string) { + function tryGiveBetterPrimaryError(errNode: Node, maybeMissingAwait: boolean, leftStr: string, rightStr: string) { + let typeName: string | undefined; switch (operatorToken.kind) { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.EqualsEqualsToken: - return error(errNode, Diagnostics.This_condition_will_always_return_0_since_the_types_1_and_2_have_no_overlap, "false", leftStr, rightStr); + typeName = "false"; + break; case SyntaxKind.ExclamationEqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: - return error(errNode, Diagnostics.This_condition_will_always_return_0_since_the_types_1_and_2_have_no_overlap, "true", leftStr, rightStr); - } + typeName = "true"; + } + + if (typeName) { + return errorAndMaybeSuggestAwait( + errNode, + maybeMissingAwait, + Diagnostics.This_condition_will_always_return_0_since_the_types_1_and_2_have_no_overlap, + typeName, leftStr, rightStr); + } + return undefined; } } @@ -27879,18 +27958,22 @@ namespace ts { // number and string input is allowed, we want to say that number is not an // array type or a string type. const yieldType = getIterationTypeOfIterable(use, IterationTypeKind.Yield, inputType, /*errorNode*/ undefined); - const diagnostic = !(use & IterationUse.AllowsStringInputFlag) || hasStringConstituent + const [defaultDiagnostic, maybeMissingAwait]: [DiagnosticMessage, boolean] = !(use & IterationUse.AllowsStringInputFlag) || hasStringConstituent ? downlevelIteration - ? Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator + ? [Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true] : yieldType - ? Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_Use_compiler_option_downlevelIteration_to_allow_iterating_of_iterators - : Diagnostics.Type_0_is_not_an_array_type + ? [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_Use_compiler_option_downlevelIteration_to_allow_iterating_of_iterators, false] + : [Diagnostics.Type_0_is_not_an_array_type, true] : downlevelIteration - ? Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator + ? [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true] : yieldType - ? Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_Use_compiler_option_downlevelIteration_to_allow_iterating_of_iterators - : Diagnostics.Type_0_is_not_an_array_type_or_a_string_type; - error(errorNode, diagnostic, typeToString(arrayType)); + ? [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_Use_compiler_option_downlevelIteration_to_allow_iterating_of_iterators, false] + : [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type, true]; + errorAndMaybeSuggestAwait( + errorNode, + maybeMissingAwait && !!getAwaitedTypeOfPromise(arrayType), + defaultDiagnostic, + typeToString(arrayType)); } return hasStringConstituent ? stringType : undefined; } @@ -28189,9 +28272,10 @@ namespace ts { } function reportTypeNotIterableError(errorNode: Node, type: Type, allowAsyncIterables: boolean): void { - error(errorNode, allowAsyncIterables + const message = allowAsyncIterables ? Diagnostics.Type_0_must_have_a_Symbol_asyncIterator_method_that_returns_an_async_iterator - : Diagnostics.Type_0_must_have_a_Symbol_iterator_method_that_returns_an_iterator, typeToString(type)); + : Diagnostics.Type_0_must_have_a_Symbol_iterator_method_that_returns_an_iterator; + errorAndMaybeSuggestAwait(errorNode, !!getAwaitedTypeOfPromise(type), message, typeToString(type)); } /** diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 3b426f2d0c6be..c3396a70731a7 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2693,6 +2693,10 @@ "category": "Error", "code": 2772 }, + "Did you forget to use 'await'?": { + "category": "Error", + "code": 2773 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/operationsAvailableOnPromisedType.errors.txt b/tests/baselines/reference/operationsAvailableOnPromisedType.errors.txt new file mode 100644 index 0000000000000..0fc56b82c1de6 --- /dev/null +++ b/tests/baselines/reference/operationsAvailableOnPromisedType.errors.txt @@ -0,0 +1,104 @@ +tests/cases/compiler/operationsAvailableOnPromisedType.ts(11,9): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(12,5): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(13,5): error TS2365: Operator '+' cannot be applied to types 'number' and 'Promise'. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(14,5): error TS2365: Operator '>' cannot be applied to types 'number' and 'Promise'. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(15,5): error TS2356: An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(16,7): error TS2356: An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(17,5): error TS2367: This condition will always return 'false' since the types 'number' and 'Promise' have no overlap. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(18,9): error TS2461: Type 'Promise' is not an array type. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(19,21): error TS2495: Type 'Promise' is not an array type or a string type. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(20,12): error TS2345: Argument of type 'Promise' is not assignable to parameter of type 'number'. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(21,11): error TS2570: Property 'prop' does not exist on type 'Promise<{ prop: string; }>'. Did you forget to use 'await'? +tests/cases/compiler/operationsAvailableOnPromisedType.ts(23,27): error TS2495: Type 'Promise' is not an array type or a string type. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(24,5): error TS2349: This expression is not callable. + Type 'Promise<() => void>' has no call signatures. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(25,5): error TS2349: This expression is not callable. + Not all constituents of type 'Promise<() => void> | (() => void)' are callable. + Type 'Promise<() => void>' has no call signatures. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(26,9): error TS2351: This expression is not constructable. + Type 'Promise any>' has no construct signatures. +tests/cases/compiler/operationsAvailableOnPromisedType.ts(27,5): error TS2349: This expression is not callable. + Type 'Promise' has no call signatures. + + +==== tests/cases/compiler/operationsAvailableOnPromisedType.ts (16 errors) ==== + async function fn( + a: number, + b: Promise, + c: Promise, + d: Promise<{ prop: string }>, + e: Promise<() => void>, + f: Promise<() => void> | (() => void), + g: Promise<{ new(): any }> + ) { + // All errors + a | b; + ~ +!!! error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:11:9: Did you forget to use 'await'? + b | a; + ~ +!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:12:5: Did you forget to use 'await'? + a + b; + ~~~~~ +!!! error TS2365: Operator '+' cannot be applied to types 'number' and 'Promise'. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:13:5: Did you forget to use 'await'? + a > b; + ~~~~~ +!!! error TS2365: Operator '>' cannot be applied to types 'number' and 'Promise'. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:14:5: Did you forget to use 'await'? + b++; + ~ +!!! error TS2356: An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:15:5: Did you forget to use 'await'? + --b; + ~ +!!! error TS2356: An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:16:7: Did you forget to use 'await'? + a === b; + ~~~~~~~ +!!! error TS2367: This condition will always return 'false' since the types 'number' and 'Promise' have no overlap. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:17:5: Did you forget to use 'await'? + [...c]; + ~ +!!! error TS2461: Type 'Promise' is not an array type. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:18:9: Did you forget to use 'await'? + for (const s of c) { + ~ +!!! error TS2495: Type 'Promise' is not an array type or a string type. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:19:21: Did you forget to use 'await'? + fn(b, b, c, d, e, f, g); + ~ +!!! error TS2345: Argument of type 'Promise' is not assignable to parameter of type 'number'. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:20:12: Did you forget to use 'await'? + d.prop; + ~~~~ +!!! error TS2570: Property 'prop' does not exist on type 'Promise<{ prop: string; }>'. Did you forget to use 'await'? + } + for await (const s of c) {} + ~ +!!! error TS2495: Type 'Promise' is not an array type or a string type. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:23:27: Did you forget to use 'await'? + e(); + ~ +!!! error TS2349: This expression is not callable. +!!! error TS2349: Type 'Promise<() => void>' has no call signatures. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:24:5: Did you forget to use 'await'? + f(); + ~ +!!! error TS2349: This expression is not callable. +!!! error TS2349: Not all constituents of type 'Promise<() => void> | (() => void)' are callable. +!!! error TS2349: Type 'Promise<() => void>' has no call signatures. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:25:5: Did you forget to use 'await'? + new g(); + ~ +!!! error TS2351: This expression is not constructable. +!!! error TS2351: Type 'Promise any>' has no construct signatures. +!!! related TS2773 tests/cases/compiler/operationsAvailableOnPromisedType.ts:26:9: Did you forget to use 'await'? + b(); + ~ +!!! error TS2349: This expression is not callable. +!!! error TS2349: Type 'Promise' has no call signatures. + } + \ No newline at end of file diff --git a/tests/baselines/reference/operationsAvailableOnPromisedType.js b/tests/baselines/reference/operationsAvailableOnPromisedType.js new file mode 100644 index 0000000000000..c9f8851fcc860 --- /dev/null +++ b/tests/baselines/reference/operationsAvailableOnPromisedType.js @@ -0,0 +1,141 @@ +//// [operationsAvailableOnPromisedType.ts] +async function fn( + a: number, + b: Promise, + c: Promise, + d: Promise<{ prop: string }>, + e: Promise<() => void>, + f: Promise<() => void> | (() => void), + g: Promise<{ new(): any }> +) { + // All errors + a | b; + b | a; + a + b; + a > b; + b++; + --b; + a === b; + [...c]; + for (const s of c) { + fn(b, b, c, d, e, f, g); + d.prop; + } + for await (const s of c) {} + e(); + f(); + new g(); + b(); +} + + +//// [operationsAvailableOnPromisedType.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __asyncValues = (this && this.__asyncValues) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +function fn(a, b, c, d, e, f, g) { + var c_1, c_1_1; + var e_1, _a; + return __awaiter(this, void 0, void 0, function () { + var _i, c_2, s, s, e_1_1; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + // All errors + a | b; + b | a; + a + b; + a > b; + b++; + --b; + a === b; + __spreadArrays(c); + for (_i = 0, c_2 = c; _i < c_2.length; _i++) { + s = c_2[_i]; + fn(b, b, c, d, e, f, g); + d.prop; + } + _b.label = 1; + case 1: + _b.trys.push([1, 6, 7, 12]); + c_1 = __asyncValues(c); + _b.label = 2; + case 2: return [4 /*yield*/, c_1.next()]; + case 3: + if (!(c_1_1 = _b.sent(), !c_1_1.done)) return [3 /*break*/, 5]; + s = c_1_1.value; + _b.label = 4; + case 4: return [3 /*break*/, 2]; + case 5: return [3 /*break*/, 12]; + case 6: + e_1_1 = _b.sent(); + e_1 = { error: e_1_1 }; + return [3 /*break*/, 12]; + case 7: + _b.trys.push([7, , 10, 11]); + if (!(c_1_1 && !c_1_1.done && (_a = c_1["return"]))) return [3 /*break*/, 9]; + return [4 /*yield*/, _a.call(c_1)]; + case 8: + _b.sent(); + _b.label = 9; + case 9: return [3 /*break*/, 11]; + case 10: + if (e_1) throw e_1.error; + return [7 /*endfinally*/]; + case 11: return [7 /*endfinally*/]; + case 12: + e(); + f(); + new g(); + b(); + return [2 /*return*/]; + } + }); + }); +} diff --git a/tests/baselines/reference/operationsAvailableOnPromisedType.symbols b/tests/baselines/reference/operationsAvailableOnPromisedType.symbols new file mode 100644 index 0000000000000..87c0aa129b490 --- /dev/null +++ b/tests/baselines/reference/operationsAvailableOnPromisedType.symbols @@ -0,0 +1,97 @@ +=== tests/cases/compiler/operationsAvailableOnPromisedType.ts === +async function fn( +>fn : Symbol(fn, Decl(operationsAvailableOnPromisedType.ts, 0, 0)) + + a: number, +>a : Symbol(a, Decl(operationsAvailableOnPromisedType.ts, 0, 18)) + + b: Promise, +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + + c: Promise, +>c : Symbol(c, Decl(operationsAvailableOnPromisedType.ts, 2, 23)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + + d: Promise<{ prop: string }>, +>d : Symbol(d, Decl(operationsAvailableOnPromisedType.ts, 3, 25)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) +>prop : Symbol(prop, Decl(operationsAvailableOnPromisedType.ts, 4, 16)) + + e: Promise<() => void>, +>e : Symbol(e, Decl(operationsAvailableOnPromisedType.ts, 4, 33)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + + f: Promise<() => void> | (() => void), +>f : Symbol(f, Decl(operationsAvailableOnPromisedType.ts, 5, 27)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + + g: Promise<{ new(): any }> +>g : Symbol(g, Decl(operationsAvailableOnPromisedType.ts, 6, 42)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + +) { + // All errors + a | b; +>a : Symbol(a, Decl(operationsAvailableOnPromisedType.ts, 0, 18)) +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) + + b | a; +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) +>a : Symbol(a, Decl(operationsAvailableOnPromisedType.ts, 0, 18)) + + a + b; +>a : Symbol(a, Decl(operationsAvailableOnPromisedType.ts, 0, 18)) +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) + + a > b; +>a : Symbol(a, Decl(operationsAvailableOnPromisedType.ts, 0, 18)) +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) + + b++; +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) + + --b; +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) + + a === b; +>a : Symbol(a, Decl(operationsAvailableOnPromisedType.ts, 0, 18)) +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) + + [...c]; +>c : Symbol(c, Decl(operationsAvailableOnPromisedType.ts, 2, 23)) + + for (const s of c) { +>s : Symbol(s, Decl(operationsAvailableOnPromisedType.ts, 18, 14)) +>c : Symbol(c, Decl(operationsAvailableOnPromisedType.ts, 2, 23)) + + fn(b, b, c, d, e, f, g); +>fn : Symbol(fn, Decl(operationsAvailableOnPromisedType.ts, 0, 0)) +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) +>c : Symbol(c, Decl(operationsAvailableOnPromisedType.ts, 2, 23)) +>d : Symbol(d, Decl(operationsAvailableOnPromisedType.ts, 3, 25)) +>e : Symbol(e, Decl(operationsAvailableOnPromisedType.ts, 4, 33)) +>f : Symbol(f, Decl(operationsAvailableOnPromisedType.ts, 5, 27)) +>g : Symbol(g, Decl(operationsAvailableOnPromisedType.ts, 6, 42)) + + d.prop; +>d : Symbol(d, Decl(operationsAvailableOnPromisedType.ts, 3, 25)) + } + for await (const s of c) {} +>s : Symbol(s, Decl(operationsAvailableOnPromisedType.ts, 22, 20)) +>c : Symbol(c, Decl(operationsAvailableOnPromisedType.ts, 2, 23)) + + e(); +>e : Symbol(e, Decl(operationsAvailableOnPromisedType.ts, 4, 33)) + + f(); +>f : Symbol(f, Decl(operationsAvailableOnPromisedType.ts, 5, 27)) + + new g(); +>g : Symbol(g, Decl(operationsAvailableOnPromisedType.ts, 6, 42)) + + b(); +>b : Symbol(b, Decl(operationsAvailableOnPromisedType.ts, 1, 14)) +} + diff --git a/tests/baselines/reference/operationsAvailableOnPromisedType.types b/tests/baselines/reference/operationsAvailableOnPromisedType.types new file mode 100644 index 0000000000000..b22bd7fb1ccb6 --- /dev/null +++ b/tests/baselines/reference/operationsAvailableOnPromisedType.types @@ -0,0 +1,107 @@ +=== tests/cases/compiler/operationsAvailableOnPromisedType.ts === +async function fn( +>fn : (a: number, b: Promise, c: Promise, d: Promise<{ prop: string; }>, e: Promise<() => void>, f: Promise<() => void> | (() => void), g: Promise any>) => Promise + + a: number, +>a : number + + b: Promise, +>b : Promise + + c: Promise, +>c : Promise + + d: Promise<{ prop: string }>, +>d : Promise<{ prop: string; }> +>prop : string + + e: Promise<() => void>, +>e : Promise<() => void> + + f: Promise<() => void> | (() => void), +>f : Promise<() => void> | (() => void) + + g: Promise<{ new(): any }> +>g : Promise any> + +) { + // All errors + a | b; +>a | b : number +>a : number +>b : Promise + + b | a; +>b | a : number +>b : Promise +>a : number + + a + b; +>a + b : any +>a : number +>b : Promise + + a > b; +>a > b : boolean +>a : number +>b : Promise + + b++; +>b++ : number +>b : Promise + + --b; +>--b : number +>b : Promise + + a === b; +>a === b : boolean +>a : number +>b : Promise + + [...c]; +>[...c] : any[] +>...c : any +>c : Promise + + for (const s of c) { +>s : any +>c : Promise + + fn(b, b, c, d, e, f, g); +>fn(b, b, c, d, e, f, g) : Promise +>fn : (a: number, b: Promise, c: Promise, d: Promise<{ prop: string; }>, e: Promise<() => void>, f: Promise<() => void> | (() => void), g: Promise any>) => Promise +>b : Promise +>b : Promise +>c : Promise +>d : Promise<{ prop: string; }> +>e : Promise<() => void> +>f : Promise<() => void> | (() => void) +>g : Promise any> + + d.prop; +>d.prop : any +>d : Promise<{ prop: string; }> +>prop : any + } + for await (const s of c) {} +>s : any +>c : Promise + + e(); +>e() : any +>e : Promise<() => void> + + f(); +>f() : any +>f : Promise<() => void> | (() => void) + + new g(); +>new g() : any +>g : Promise any> + + b(); +>b() : any +>b : Promise +} + diff --git a/tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt b/tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt index c8c4ed39ed7e1..1ca77aebc86fe 100644 --- a/tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt +++ b/tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt @@ -72,6 +72,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts( yield* Promise.resolve([1, 2]); ~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2504: Type 'Promise' must have a '[Symbol.asyncIterator]()' method that returns an async iterator. +!!! related TS2773 tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts:8:12: Did you forget to use 'await'? } const assignability1: () => AsyncIterableIterator = async function * () { ~~~~~~~~~~~~~~ diff --git a/tests/cases/compiler/nonexistentPropertyAvailableOnPromisedType.ts b/tests/cases/compiler/nonexistentPropertyAvailableOnPromisedType.ts deleted file mode 100644 index 476f4ac563617..0000000000000 --- a/tests/cases/compiler/nonexistentPropertyAvailableOnPromisedType.ts +++ /dev/null @@ -1,3 +0,0 @@ -function f(x: Promise) { - x.toLowerCase(); -} diff --git a/tests/cases/compiler/operationsAvailableOnPromisedType.ts b/tests/cases/compiler/operationsAvailableOnPromisedType.ts new file mode 100644 index 0000000000000..b0bd677cf8dbd --- /dev/null +++ b/tests/cases/compiler/operationsAvailableOnPromisedType.ts @@ -0,0 +1,28 @@ +async function fn( + a: number, + b: Promise, + c: Promise, + d: Promise<{ prop: string }>, + e: Promise<() => void>, + f: Promise<() => void> | (() => void), + g: Promise<{ new(): any }> +) { + // All errors + a | b; + b | a; + a + b; + a > b; + b++; + --b; + a === b; + [...c]; + for (const s of c) { + fn(b, b, c, d, e, f, g); + d.prop; + } + for await (const s of c) {} + e(); + f(); + new g(); + b(); +}