Error on emit declaration of extends class w/o symbol

Error when emitting an extends clause for a type that has no symbol.
This error only occurs on exported classes.
This prevents the emitter from producing types that extend from
intersections, which are not parseable right now.
This commit is contained in:
Nathan Shively-Sanders 2017-02-14 12:42:32 -08:00
parent 58b8a54e5f
commit cd272e8244
6 changed files with 29 additions and 7 deletions

View file

@ -20844,6 +20844,9 @@ namespace ts {
const classType = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(node));
resolveBaseTypesOfClass(classType);
const baseType = classType.resolvedBaseTypes.length ? classType.resolvedBaseTypes[0] : unknownType;
if (!baseType.symbol) {
writer.reportIllegalExtends();
}
getSymbolDisplayBuilder().buildTypeDisplay(baseType, writer, enclosingDeclaration, flags);
}

View file

@ -190,6 +190,7 @@ namespace ts {
const writer = <EmitTextWriterWithSymbolWriter>createTextWriter(newLine);
writer.trackSymbol = trackSymbol;
writer.reportInaccessibleThisError = reportInaccessibleThisError;
writer.reportIllegalExtends = reportIllegalExtends;
writer.writeKeyword = writer.write;
writer.writeOperator = writer.write;
writer.writePunctuation = writer.write;
@ -313,6 +314,14 @@ namespace ts {
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning));
}
function reportIllegalExtends() {
if (errorNameNode) {
reportedDeclarationError = true;
emitterDiagnostics.add(createDiagnosticForNode(errorNameNode, Diagnostics.Extends_clause_of_exported_class_0_refers_to_a_type_with_no_declaration,
declarationNameToString(errorNameNode)));
}
}
function reportInaccessibleThisError() {
if (errorNameNode) {
reportedDeclarationError = true;
@ -1071,7 +1080,7 @@ namespace ts {
}
}
function emitHeritageClause(typeReferences: ExpressionWithTypeArguments[], isImplementsList: boolean) {
function emitHeritageClause(className: Identifier, typeReferences: ExpressionWithTypeArguments[], isImplementsList: boolean) {
if (typeReferences) {
write(isImplementsList ? " implements " : " extends ");
emitCommaList(typeReferences, emitTypeOfTypeReference);
@ -1086,7 +1095,9 @@ namespace ts {
}
else {
writer.getSymbolAccessibilityDiagnostic = getHeritageClauseVisibilityError;
errorNameNode = className;
resolver.writeBaseConstructorTypeOfClass(<ClassLikeDeclaration>enclosingDeclaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue, writer);
errorNameNode = undefined;
}
function getHeritageClauseVisibilityError(): SymbolAccessibilityDiagnostic {
@ -1136,9 +1147,10 @@ namespace ts {
emitTypeParameters(node.typeParameters);
const baseTypeNode = getClassExtendsHeritageClauseElement(node);
if (baseTypeNode) {
emitHeritageClause([baseTypeNode], /*isImplementsList*/ false);
node.name
emitHeritageClause(node.name, [baseTypeNode], /*isImplementsList*/ false);
}
emitHeritageClause(getClassImplementsHeritageClauseElements(node), /*isImplementsList*/ true);
emitHeritageClause(node.name, getClassImplementsHeritageClauseElements(node), /*isImplementsList*/ true);
write(" {");
writeLine();
increaseIndent();
@ -1160,7 +1172,7 @@ namespace ts {
emitTypeParameters(node.typeParameters);
const interfaceExtendsTypes = filter(getInterfaceBaseTypeNodes(node), base => isEntityNameExpression(base.expression));
if (interfaceExtendsTypes && interfaceExtendsTypes.length) {
emitHeritageClause(interfaceExtendsTypes, /*isImplementsList*/ false);
emitHeritageClause(node.name, interfaceExtendsTypes, /*isImplementsList*/ false);
}
write(" {");
writeLine();

View file

@ -2352,6 +2352,10 @@
"category": "Error",
"code": 4092
},
"Extends clause of exported class '{0}' refers to a type with no declaration.": {
"category": "Error",
"code": 4093
},
"The current host does not support the '{0}' option.": {
"category": "Error",

View file

@ -2459,6 +2459,7 @@
// with import statements it previously saw (but chose not to emit).
trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
reportInaccessibleThisError(): void;
reportIllegalExtends(): void;
}
export const enum TypeFormatFlags {

View file

@ -53,7 +53,8 @@ namespace ts {
decreaseIndent: noop,
clear: () => str = "",
trackSymbol: noop,
reportInaccessibleThisError: noop
reportInaccessibleThisError: noop,
reportIllegalExtends: noop
};
}

View file

@ -1166,7 +1166,8 @@ namespace ts {
decreaseIndent: () => { indent--; },
clear: resetWriter,
trackSymbol: noop,
reportInaccessibleThisError: noop
reportInaccessibleThisError: noop,
reportIllegalExtends: noop
};
function writeIndent() {
@ -1386,4 +1387,4 @@ namespace ts {
// First token is the open curly, this is where we want to put the 'super' call.
return constructor.body.getFirstToken(sourceFile).getEnd();
}
}
}