diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1e5d5984ab7..2cdee150af6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7532,9 +7532,10 @@ namespace ts { getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent).symbol)) : undefined; const typeParameters = classType ? classType.localTypeParameters : getTypeParametersFromDeclaration(declaration); - const returnType = getSignatureReturnTypeFromDeclaration(declaration, isJSConstructSignature, classType); const hasRestLikeParameter = hasRestParameter(declaration) || isInJavaScriptFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters); - links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, returnType, /*resolvedTypePredicate*/ undefined, minArgumentCount, hasRestLikeParameter, hasLiteralTypes); + links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, + /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, + minArgumentCount, hasRestLikeParameter, hasLiteralTypes); } return links.resolvedSignature; } @@ -7564,34 +7565,6 @@ namespace ts { return true; } - function getSignatureReturnTypeFromDeclaration(declaration: SignatureDeclaration | JSDocSignature, isJSConstructSignature: boolean, classType: Type | undefined) { - if (isJSConstructSignature) { - return getTypeFromTypeNode((declaration.parameters[0] as ParameterDeclaration).type!); // TODO: GH#18217 - } - else if (classType) { - return classType; - } - - const typeNode = getEffectiveReturnTypeNode(declaration); - if (typeNode) { - return getTypeFromTypeNode(typeNode); - } - - // TypeScript 1.0 spec (April 2014): - // If only one accessor includes a type annotation, the other behaves as if it had the same type annotation. - if (declaration.kind === SyntaxKind.GetAccessor && !hasNonBindableDynamicName(declaration)) { - const setter = getDeclarationOfKind(getSymbolOfNode(declaration), SyntaxKind.SetAccessor); - return getAnnotatedAccessorType(setter); - } - const typeFromTag = getReturnTypeOfTypeTag(declaration); - if (typeFromTag) { - return typeFromTag; - } - if (nodeIsMissing((declaration).body)) { - return anyType; - } - } - function getReturnTypeOfTypeTag(node: SignatureDeclaration | JSDocSignature) { const typeTag = isInJavaScriptFile(node) ? getJSDocTypeTag(node) : undefined; const signatures = typeTag && typeTag.typeExpression && getSignaturesOfType(getTypeFromTypeNode(typeTag.typeExpression), SignatureKind.Call); @@ -7696,34 +7669,61 @@ namespace ts { if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { return errorType; } - let type: Type; - if (signature.target) { - type = instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper!); - } - else if (signature.unionSignatures) { - type = getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype); - } - else { - type = getReturnTypeFromBody(signature.declaration); - } + let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper!) : + signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) : + getReturnTypeFromAnnotationOrBody(signature.declaration!); if (!popTypeResolution()) { - type = anyType; - if (noImplicitAny) { - const declaration = signature.declaration; - const name = getNameOfDeclaration(declaration); - if (name) { - error(name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(name)); + if (signature.declaration) { + const typeNode = getEffectiveReturnTypeNode(signature.declaration); + if (typeNode) { + error(typeNode, Diagnostics.Return_type_annotation_circularly_references_itself); } - else { - error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions); + else if (noImplicitAny) { + const declaration = signature.declaration; + const name = getNameOfDeclaration(declaration); + if (name) { + error(name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(name)); + } + else { + error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions); + } } } + type = anyType; } signature.resolvedReturnType = type; } return signature.resolvedReturnType; } + function getReturnTypeFromAnnotationOrBody(declaration: SignatureDeclaration | JSDocSignature) { + if (declaration.kind === SyntaxKind.Constructor) { + return getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent).symbol)) + } + if (isJSDocConstructSignature(declaration)) { + return getTypeFromTypeNode((declaration.parameters[0] as ParameterDeclaration).type!); // TODO: GH#18217 + } + const typeNode = getEffectiveReturnTypeNode(declaration); + if (typeNode) { + return getTypeFromTypeNode(typeNode); + } + if (declaration.kind === SyntaxKind.GetAccessor && !hasNonBindableDynamicName(declaration)) { + const setter = getDeclarationOfKind(getSymbolOfNode(declaration), SyntaxKind.SetAccessor); + const setterType = getAnnotatedAccessorType(setter); + if (setterType) { + return setterType; + } + } + const typeFromTag = getReturnTypeOfTypeTag(declaration); + if (typeFromTag) { + return typeFromTag; + } + if (nodeIsMissing((declaration).body)) { + return anyType; + } + return getReturnTypeFromBody(declaration); + } + function isResolvingReturnTypeOfSignature(signature: Signature) { return !signature.resolvedReturnType && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0; } @@ -20674,7 +20674,7 @@ namespace ts { contextualSignature : instantiateSignature(contextualSignature, contextualMapper); assignContextualParameterTypes(signature, instantiatedContextualSignature); } - if (!getEffectiveReturnTypeNode(node) && !signature.resolvedReturnType) { + if (!getReturnOrPromisedType(node, getFunctionFlags(node)) && !signature.resolvedReturnType) { const returnType = getReturnTypeFromBody(node, checkMode); if (!signature.resolvedReturnType) { signature.resolvedReturnType = returnType; @@ -22661,6 +22661,10 @@ namespace ts { checkTypeAssignableTo(constraintType, keyofConstraintType, node.typeParameter.constraint); } + function checkThisType(node: ThisTypeNode) { + getTypeFromThisTypeNode(node); + } + function checkTypeOperator(node: TypeOperatorNode) { checkGrammarTypeOperatorNode(node); checkSourceElement(node.type); @@ -26533,6 +26537,8 @@ namespace ts { case SyntaxKind.OptionalType: case SyntaxKind.RestType: return checkSourceElement((node).type); + case SyntaxKind.ThisType: + return checkThisType(node); case SyntaxKind.TypeOperator: return checkTypeOperator(node); case SyntaxKind.ConditionalType: diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index bfac297b13b..9bba4f34939 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2064,6 +2064,10 @@ "category": "Error", "code": 2575 }, + "Return type annotation circularly references itself.": { + "category": "Error", + "code": 2576 + }, "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0ac533f7658..1a0f197f580 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3374,10 +3374,9 @@ namespace ts { * JavaScript file, gets the return type annotation from JSDoc. */ export function getEffectiveReturnTypeNode(node: SignatureDeclaration | JSDocSignature): TypeNode | undefined { - if (isJSDocSignature(node)) { - return node.type && node.type.typeExpression && node.type.typeExpression.type; - } - return node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined); + return isJSDocSignature(node) ? + node.type && node.type.typeExpression && node.type.typeExpression.type : + node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined); } export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray {