diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ca665346036..d8b3785a89e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -968,37 +968,34 @@ namespace ts { function checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean { - const parentExpression = climbToSupportedExpressionWithTypeArguments(errorLocation); - if (!parentExpression) { - return false; - } - const expression = parentExpression.expression; - - if (resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)) { + const expression = climbToEntityNameOfExpressionWithTypeArguments(errorLocation); + const isError = !!(expression && resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)); + if (isError) { error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression)); - return true; } - return false; + return isError; } /** - * Climbs up parents to a SupportedExpressionWIthTypeArguments. - * Does *not* just climb to an ExpressionWithTypeArguments; instead, ensures that this really is supported. + * Climbs up parents to an ExpressionWithTypeArguments, and returns its expression, + * but returns undefined if that expression is not an EntityNameExpression. */ - function climbToSupportedExpressionWithTypeArguments(node: Node): SupportedExpressionWithTypeArguments | undefined { - while (node) { - switch (node.kind) { - case SyntaxKind.Identifier: - case SyntaxKind.PropertyAccessExpression: + function climbToEntityNameOfExpressionWithTypeArguments(node: Node): EntityNameExpression | undefined { + switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.PropertyAccessExpression: + if (node.parent) { node = node.parent; - break; - case SyntaxKind.ExpressionWithTypeArguments: - Debug.assert(isSupportedExpressionWithTypeArguments(node)); - return node; - default: + } + else { return undefined; - } + } + break; + case SyntaxKind.ExpressionWithTypeArguments: + Debug.assert(isEntityNameExpression((node).expression)); + return (node).expression; + default: + return undefined; } - return undefined; } @@ -3686,7 +3683,7 @@ namespace ts { const baseTypeNodes = getInterfaceBaseTypeNodes(declaration); if (baseTypeNodes) { for (const node of baseTypeNodes) { - if (isSupportedExpressionWithTypeArguments(node)) { + if (isEntityNameExpression(node.expression)) { const baseSymbol = resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true); if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) { return false; @@ -5042,9 +5039,9 @@ namespace ts { case SyntaxKind.ExpressionWithTypeArguments: // We only support expressions that are simple qualified names. For other // expressions this produces undefined. - const expr = node; - if (isSupportedExpressionWithTypeArguments(expr)) { - return expr.expression; + const expr = (node).expression; + if (isEntityNameExpression(expr)) { + return expr; } // fall through; @@ -5101,8 +5098,8 @@ namespace ts { // We only support expressions that are simple qualified names. For other expressions this produces undefined. const typeNameOrExpression: EntityNameOrEntityNameExpression = node.kind === SyntaxKind.TypeReference ? (node).typeName - : isSupportedExpressionWithTypeArguments(node) - ? (node).expression + : isEntityNameExpression((node).expression) + ? (node).expression : undefined; symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol; type = symbol === unknownSymbol ? unknownType : @@ -16255,7 +16252,7 @@ namespace ts { const implementedTypeNodes = getClassImplementsHeritageClauseElements(node); if (implementedTypeNodes) { for (const typeRefNode of implementedTypeNodes) { - if (!isSupportedExpressionWithTypeArguments(typeRefNode)) { + if (!isEntityNameExpression(typeRefNode.expression)) { error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); } checkTypeReferenceNode(typeRefNode); @@ -16497,7 +16494,7 @@ namespace ts { checkObjectTypeForDuplicateDeclarations(node); } forEach(getInterfaceBaseTypeNodes(node), heritageElement => { - if (!isSupportedExpressionWithTypeArguments(heritageElement)) { + if (!isEntityNameExpression(heritageElement.expression)) { error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); } checkTypeReferenceNode(heritageElement); diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 220244c55af..c93784cd9e0 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -452,7 +452,7 @@ namespace ts { } function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) { - if (isSupportedExpressionWithTypeArguments(node)) { + if (isEntityNameExpression(node.expression)) { Debug.assert(node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression); emitEntityName(node.expression); if (node.typeArguments) { @@ -1019,7 +1019,7 @@ namespace ts { } function emitTypeOfTypeReference(node: ExpressionWithTypeArguments) { - if (isSupportedExpressionWithTypeArguments(node)) { + if (isEntityNameExpression(node.expression)) { emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError); } else if (!isImplementsList && node.expression.kind === SyntaxKind.NullKeyword) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 983ed25c848..804989570d8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1014,10 +1014,6 @@ namespace ts { expression: LeftHandSideExpression; typeArguments?: NodeArray; } - export interface SupportedExpressionWithTypeArguments extends ExpressionWithTypeArguments { - _supportedExpressionWithTypeArgumentsBrand?: any; - expression: EntityNameExpression; - } // @kind(SyntaxKind.NewExpression) export interface NewExpression extends CallExpression, PrimaryExpression { } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 466cf8c2b77..f946e4b614f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1039,8 +1039,8 @@ namespace ts { case SyntaxKind.TypeReference: return (node).typeName; case SyntaxKind.ExpressionWithTypeArguments: - Debug.assert(isSupportedExpressionWithTypeArguments(node)); - return (node).expression; + Debug.assert(isEntityNameExpression((node).expression)); + return (node).expression; case SyntaxKind.Identifier: case SyntaxKind.QualifiedName: return (node); @@ -2684,10 +2684,6 @@ namespace ts { isClassLike(node.parent.parent); } - export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): node is SupportedExpressionWithTypeArguments { - return isEntityNameExpression(node.expression); - } - export function isEntityNameExpression(node: Expression): node is EntityNameExpression { for (; ; ) { switch (node.kind) { @@ -2702,10 +2698,6 @@ namespace ts { } } - export function isPropertyAccessAnEntityNameExpression(node: PropertyAccessExpression): node is PropertyAccessEntityNameExpression { - return isEntityNameExpression(node.expression); - } - export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) { return (node.parent.kind === SyntaxKind.QualifiedName && (node.parent).right === node) || (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent).name === node);