diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0ddea8baf08..21255d5ed94 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -883,13 +883,13 @@ module ts { if (accessibleSymbolChain) { var hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]); if (!hasAccessibleDeclarations) { - return { + return { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined, }; } - return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: hasAccessibleDeclarations.aliasesToMakeVisible }; + return hasAccessibleDeclarations; } // If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible. @@ -946,12 +946,12 @@ module ts { (declaration.kind === SyntaxKind.SourceFile && isExternalModule(declaration)); } - function hasVisibleDeclarations(symbol: Symbol): { aliasesToMakeVisible?: ImportDeclaration[]; } { + function hasVisibleDeclarations(symbol: Symbol): SymbolVisibilityResult { var aliasesToMakeVisible: ImportDeclaration[]; if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) { return undefined; } - return { aliasesToMakeVisible: aliasesToMakeVisible }; + return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: aliasesToMakeVisible }; function getIsDeclarationVisible(declaration: Declaration) { if (!isDeclarationVisible(declaration)) { @@ -980,14 +980,50 @@ module ts { } } - function isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult { + function isEntityNameVisible(entityName: EntityName, enclosingDeclaration: Node): SymbolVisibilityResult { + // get symbol of the first identifier of the entityName + var meaning: SymbolFlags; + if (entityName.parent.kind === SyntaxKind.TypeQuery) { + // Typeof value + meaning = SymbolFlags.Value | SymbolFlags.ExportValue; + } + else if (entityName.kind === SyntaxKind.QualifiedName || + entityName.parent.kind === SyntaxKind.ImportDeclaration) { + // Left identifier from type reference or TypeAlias + // Entity name of the import declaration + meaning = SymbolFlags.Namespace; + } + else { + // Type Reference or TypeAlias entity = Identifier + meaning = SymbolFlags.Type; + } var firstIdentifier = getFirstIdentifier(entityName); - var symbolOfNameSpace = resolveName(entityName.parent, (firstIdentifier).text, SymbolFlags.Namespace, Diagnostics.Cannot_find_name_0, firstIdentifier); + var symbol = resolveName(enclosingDeclaration, (firstIdentifier).text, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); + // Verify if the symbol is accessible - var hasNamespaceDeclarationsVisibile = hasVisibleDeclarations(symbolOfNameSpace); - return hasNamespaceDeclarationsVisibile ? - { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: hasNamespaceDeclarationsVisibile.aliasesToMakeVisible } : - { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: declarationNameToString(firstIdentifier) }; + var isVisible = hasVisibleDeclarations(symbol); + if (isVisible) { + return isVisible; + } + + // Not visible populate error info + var errorSymbolName: string; + var errorModuleName: string; + // TODO(shkamat) For now lets just do this for alias declarations, but in all cases only first identifier text should be enough + if (entityName.parent.kind === SyntaxKind.ImportDeclaration) { + errorSymbolName = getTextOfNode(firstIdentifier); + } + else { + errorSymbolName = getTextOfNode(entityName); + errorModuleName = entityName.kind === SyntaxKind.QualifiedName ? + getTextOfNode(firstIdentifier) : + undefined; + } + return { + accessibility: SymbolAccessibility.NotAccessible, + errorSymbolName: errorSymbolName, + errorModuleName: errorModuleName + }; } function releaseStringWriter(writer: StringSymbolWriter) { @@ -1599,6 +1635,7 @@ module ts { case SyntaxKind.IndexSignature: case SyntaxKind.Parameter: case SyntaxKind.ModuleBlock: + case SyntaxKind.TypeParameter: return isDeclarationVisible(node.parent); // Source file is always visible @@ -8918,7 +8955,7 @@ module ts { writeTypeAtLocation: writeTypeAtLocation, writeReturnTypeOfSignatureDeclaration: writeReturnTypeOfSignatureDeclaration, isSymbolAccessible: isSymbolAccessible, - isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile, + isEntityNameVisible: isEntityNameVisible, getConstantValue: getConstantValue, }; checkProgram(); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f61d4403eec..70e4d0c1328 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -6,6 +6,7 @@ module ts { interface EmitTextWriter { write(s: string): void; + writeTextOfNode(node: Node): void; writeLine(): void; increaseIndent(): void; decreaseIndent(): void; @@ -18,7 +19,15 @@ module ts { getIndent(): number; } + interface SymbolAccessibilityDiagnostic { + errorNode: Node; + diagnosticMessage: DiagnosticMessage; + typeName?: DeclarationName; + } + type GetSymbolAccessibilityDiagnostic = (symbolAccesibilityResult: SymbolAccessiblityResult) => SymbolAccessibilityDiagnostic; + interface EmitTextWriterWithSymbolWriter extends EmitTextWriter, SymbolWriter{ + getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic; } var indentStrings: string[] = ["", " "]; @@ -156,9 +165,14 @@ module ts { } } + function writeTextOfNode(node: Node) { + write(getSourceTextOfLocalNode(node)); + } + return { write: write, rawWrite: rawWrite, + writeTextOfNode: writeTextOfNode, writeLiteral: writeLiteral, writeLine: writeLine, increaseIndent: () => indent++, @@ -317,6 +331,7 @@ module ts { function emitJavaScript(jsFilePath: string, root?: SourceFile) { var writer = createTextWriter(); var write = writer.write; + var writeTextOfNode = writer.writeTextOfNode; var writeLine = writer.writeLine; var increaseIndent = writer.increaseIndent; var decreaseIndent = writer.decreaseIndent; @@ -920,7 +935,7 @@ module ts { write((node).text); } else { - write(getSourceTextOfLocalNode(node)); + writeTextOfNode(node); } write("\""); @@ -965,7 +980,7 @@ module ts { write("."); } } - write(getSourceTextOfLocalNode(node)); + writeTextOfNode(node); } function emitThis(node: Node) { @@ -2489,11 +2504,13 @@ module ts { } function emitDeclarations(jsFilePath: string, root?: SourceFile) { - var writer = createTextWriterWithSymbolWriter(); - var write = writer.write; - var writeLine = writer.writeLine; - var increaseIndent = writer.increaseIndent; - var decreaseIndent = writer.decreaseIndent; + var write: (s: string) => void; + var writeLine: () => void; + var increaseIndent: () => void; + var decreaseIndent: () => void; + var writeTextOfNode: (node: Node) => void; + + var writer = createAndSetNewTextWriterWithSymbolWriter(); var enclosingDeclaration: Node; var reportedDeclarationError = false; @@ -2507,13 +2524,7 @@ module ts { asynchronousOutput?: string; // If the output for alias was written asynchronously, the corresponding output }[] = []; - var getSymbolVisibilityDiagnosticMessage: (symbolAccesibilityResult: SymbolAccessiblityResult) => { - errorNode: Node; - diagnosticMessage: DiagnosticMessage; - typeName?: DeclarationName - } - - function createTextWriterWithSymbolWriter(): EmitTextWriterWithSymbolWriter { + function createAndSetNewTextWriterWithSymbolWriter(): EmitTextWriterWithSymbolWriter { var writer = createTextWriter(); writer.trackSymbol = trackSymbol; writer.writeKeyword = writer.write; @@ -2523,28 +2534,36 @@ module ts { writer.writeStringLiteral = writer.writeLiteral; writer.writeParameter = writer.write; writer.writeSymbol = writer.write; + setWriter(writer); return writer; } + function setWriter(newWriter: EmitTextWriterWithSymbolWriter) { + writer = newWriter; + write = newWriter.write; + writeTextOfNode = newWriter.writeTextOfNode; + writeLine = newWriter.writeLine; + increaseIndent = newWriter.increaseIndent; + decreaseIndent = newWriter.decreaseIndent; + } + function writeAsychronousImportDeclarations(importDeclarations: ImportDeclaration[]) { var oldWriter = writer; forEach(importDeclarations, aliasToWrite => { var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined); - writer = createTextWriterWithSymbolWriter(); + createAndSetNewTextWriterWithSymbolWriter(); for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) { - writer.increaseIndent(); + increaseIndent(); } writeImportDeclaration(aliasToWrite); aliasEmitInfo.asynchronousOutput = writer.getText(); }); - writer = oldWriter; + setWriter(oldWriter); } - function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { - var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning); + function handleSymbolAccessibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) { - // write the aliases if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) { writeAsychronousImportDeclarations(symbolAccesibilityResult.aliasesToMakeVisible); @@ -2553,7 +2572,7 @@ module ts { else { // Report error reportedDeclarationError = true; - var errorInfo = getSymbolVisibilityDiagnosticMessage(symbolAccesibilityResult); + var errorInfo = writer.getSymbolAccessibilityDiagnostic(symbolAccesibilityResult); if (errorInfo) { if (errorInfo.typeName) { diagnostics.push(createDiagnosticForNode(errorInfo.errorNode, @@ -2572,23 +2591,55 @@ module ts { } } + function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { + handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning)); + } + + function writeTypeAtLocation(location: Node, type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + write(": "); + if (type) { + // Write the type + emitType(type); + } + else { + resolver.writeTypeAtLocation(location, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + } + } + + function writeReturnTypeAtSignature(signature: SignatureDeclaration, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + write(": "); + if (signature.type) { + // Write the type + emitType(signature.type); + } + else { + resolver.writeReturnTypeOfSignatureDeclaration(signature, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + } + } + function emitLines(nodes: Node[]) { for (var i = 0, n = nodes.length; i < n; i++) { emitNode(nodes[i]); } } - function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void) { + function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void) { var currentWriterPos = writer.getTextPos(); for (var i = 0, n = nodes.length; i < n; i++) { if (currentWriterPos !== writer.getTextPos()) { - write(", "); + write(separator); } currentWriterPos = writer.getTextPos(); eachNodeEmitFn(nodes[i]); } } + function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void) { + emitSeparatedList(nodes, ", ", eachNodeEmitFn); + } + function writeJsDocComments(declaration: Declaration) { if (declaration) { var jsDocComments = getJsDocComments(declaration, currentSourceFile); @@ -2598,8 +2649,121 @@ module ts { } } - function emitSourceTextOfNode(node: Node) { - write(getSourceTextOfLocalNode(node)); + function emitTypeWithNewGetSymbolAccessibilityDiangostic(type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { + writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; + emitType(type); + } + + function emitType(type: TypeNode) { + switch (type.kind) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.StringLiteral: + return writeTextOfNode(type); + case SyntaxKind.TypeReference: + return emitTypeReference(type); + case SyntaxKind.TypeQuery: + return emitTypeQuery(type); + case SyntaxKind.ArrayType: + return emitArrayType(type); + case SyntaxKind.TupleType: + return emitTupleType(type); + case SyntaxKind.UnionType: + return emitUnionType(type); + case SyntaxKind.ParenType: + return emitParenType(type); + case SyntaxKind.TypeLiteral: + return emitTypeLiteral(type); + case SyntaxKind.Identifier: + return emitEntityName(type); + case SyntaxKind.QualifiedName: + return emitEntityName(type); + default: + Debug.fail("Unknown type annotation: " + type.kind); + } + + function emitEntityName(entityName: EntityName) { + var visibilityResult = resolver.isEntityNameVisible(entityName, + // Aliases can be written asynchronously so use correct enclosing declaration + entityName.parent.kind === SyntaxKind.ImportDeclaration ? entityName.parent : enclosingDeclaration); + + handleSymbolAccessibilityError(visibilityResult); + writeEntityName(entityName); + + function writeEntityName(entityName: EntityName) { + if (entityName.kind === SyntaxKind.Identifier) { + writeTextOfNode(entityName); + } + else { + var qualifiedName = entityName; + writeEntityName(qualifiedName.left); + write("."); + writeTextOfNode(qualifiedName.right); + } + } + } + + function emitTypeReference(type: TypeReferenceNode) { + emitEntityName(type.typeName); + if (type.typeArguments) { + write("<"); + emitCommaList(type.typeArguments, emitType); + write(">"); + } + } + + function emitTypeQuery(type: TypeQueryNode) { + write("typeof "); + emitEntityName(type.exprName); + } + + function emitArrayType(type: ArrayTypeNode) { + emitType(type.elementType); + write("[]"); + } + + function emitTupleType(type: TupleTypeNode) { + write("["); + emitCommaList(type.elementTypes, emitType); + write("]"); + } + + function emitUnionType(type: UnionTypeNode) { + emitSeparatedList(type.types, " | ", emitType); + } + + function emitParenType(type: ParenTypeNode) { + write("("); + emitType(type.type); + write(")"); + } + + function emitTypeLiteral(type: TypeLiteralNode) { + if (getTokenPosOfNode(type, currentSourceFile) !== skipTrivia(currentSourceFile.text, type.members.pos)) { + write("{"); + if (type.members.length) { + writeLine(); + increaseIndent(); + // write members + emitLines(type.members); + decreaseIndent(); + } + write("}"); + } + else { + // Write call/construct signature as arrow style + var signature = type.members[0]; + if (signature.kind === SyntaxKind.CallSignature) { + emitSignatureDeclaration(signature, /*arrowStyle*/true); + } + else { + emitConstructSignatureDeclaration(signature, /*arrowStyle*/ true); + } + } + } } function emitSourceFile(node: SourceFile) { @@ -2610,42 +2774,38 @@ module ts { function emitExportAssignment(node: ExportAssignment) { write("export = "); - emitSourceTextOfNode(node.exportName); + writeTextOfNode(node.exportName); write(";"); writeLine(); } - function emitDeclarationFlags(node: Declaration) { - if (node.flags & NodeFlags.Static) { - if (node.flags & NodeFlags.Private) { - write("private "); + function emitModuleElementDeclarationFlags(node: Declaration) { + // If the node is parented in the current source file we need to emit export declare or just export + if (node.parent === currentSourceFile) { + // If the node is exported + if (node.flags & NodeFlags.Export) { + write("export "); } - else if (node.flags & NodeFlags.Protected) { - write("protected "); - } - write("static "); - } - else { - if (node.flags & NodeFlags.Private) { - write("private "); - } - else if (node.flags & NodeFlags.Protected) { - write("protected "); - } - // If the node is parented in the current source file we need to emit export declare or just export - else if (node.parent === currentSourceFile) { - // If the node is exported - if (node.flags & NodeFlags.Export) { - write("export "); - } - if (node.kind !== SyntaxKind.InterfaceDeclaration) { - write("declare "); - } + if (node.kind !== SyntaxKind.InterfaceDeclaration) { + write("declare "); } } } + function emitClassMemberDeclarationFlags(node: Declaration) { + if (node.flags & NodeFlags.Private) { + write("private "); + } + else if (node.flags & NodeFlags.Protected) { + write("protected "); + } + + if (node.flags & NodeFlags.Static) { + write("static "); + } + } + function emitImportDeclaration(node: ImportDeclaration) { var nodeEmitInfo = { declaration: node, @@ -2664,52 +2824,41 @@ module ts { // correct writer especially to handle asynchronous alias writing emitJsDocComments(node); if (node.flags & NodeFlags.Export) { - writer.write("export "); + write("export "); } - writer.write("import "); - writer.write(getSourceTextOfLocalNode(node.name)); - writer.write(" = "); + write("import "); + writeTextOfNode(node.name); + write(" = "); if (node.entityName) { - checkEntityNameAccessible(); - writer.write(getSourceTextOfLocalNode(node.entityName)); - writer.write(";"); + emitTypeWithNewGetSymbolAccessibilityDiangostic(node.entityName, getImportEntityNameVisibilityError); + write(";"); } else { - writer.write("require("); - writer.write(getSourceTextOfLocalNode(node.externalModuleName)); - writer.write(");"); + write("require("); + writeTextOfNode(node.externalModuleName); + write(");"); } writer.writeLine(); - function checkEntityNameAccessible() { - var symbolAccesibilityResult = resolver.isImportDeclarationEntityNameReferenceDeclarationVisibile(node.entityName); - if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) { - // write the aliases - if (symbolAccesibilityResult.aliasesToMakeVisible) { - writeAsychronousImportDeclarations(symbolAccesibilityResult.aliasesToMakeVisible); - } - } - else { - // Report error - reportedDeclarationError = true; - diagnostics.push(createDiagnosticForNode(node, - Diagnostics.Import_declaration_0_is_using_private_name_1, - getSourceTextOfLocalNode(node.name), - symbolAccesibilityResult.errorSymbolName)); - } + function getImportEntityNameVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { + return { + diagnosticMessage: Diagnostics.Import_declaration_0_is_using_private_name_1, + errorNode: node, + typeName: node.name + }; } } function emitModuleDeclaration(node: ModuleDeclaration) { if (resolver.isDeclarationVisible(node)) { emitJsDocComments(node); - emitDeclarationFlags(node); + emitModuleElementDeclarationFlags(node); write("module "); - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); while (node.body.kind !== SyntaxKind.ModuleBlock) { node = node.body; write("."); - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); } var prevEnclosingDeclaration = enclosingDeclaration; enclosingDeclaration = node; @@ -2727,12 +2876,11 @@ module ts { function emitTypeAliasDeclaration(node: TypeAliasDeclaration) { if (resolver.isDeclarationVisible(node)) { emitJsDocComments(node); - emitDeclarationFlags(node); + emitModuleElementDeclarationFlags(node); write("type "); - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); write(" = "); - getSymbolVisibilityDiagnosticMessage = getTypeAliasDeclarationVisibilityError; - resolver.writeTypeAtLocation(node.type, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + emitTypeWithNewGetSymbolAccessibilityDiangostic(node.type, getTypeAliasDeclarationVisibilityError); write(";"); writeLine(); } @@ -2753,12 +2901,12 @@ module ts { function emitEnumDeclaration(node: EnumDeclaration) { if (resolver.isDeclarationVisible(node)) { emitJsDocComments(node); - emitDeclarationFlags(node); + emitModuleElementDeclarationFlags(node); if (isConstEnumDeclaration(node)) { write("const ") } write("enum "); - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); write(" {"); writeLine(); increaseIndent(); @@ -2771,7 +2919,7 @@ module ts { function emitEnumMemberDeclaration(node: EnumMember) { emitJsDocComments(node); - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); var enumMemberValue = resolver.getEnumMemberValue(node); if (enumMemberValue !== undefined) { write(" = "); @@ -2783,7 +2931,25 @@ module ts { function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) { function emitTypeParameter(node: TypeParameterDeclaration) { - function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { + increaseIndent(); + emitJsDocComments(node); + decreaseIndent(); + writeTextOfNode(node.name); + // If there is constraint present and this is not a type parameter of the private method emit the constraint + if (node.constraint && (node.parent.kind !== SyntaxKind.Method || !(node.parent.flags & NodeFlags.Private))) { + write(" extends "); + if (node.parent.parent && node.parent.parent.kind === SyntaxKind.TypeLiteral) { + Debug.assert(node.parent.kind === SyntaxKind.Method || + node.parent.kind === SyntaxKind.CallSignature || + node.parent.kind === SyntaxKind.ConstructSignature); + emitType(node.constraint); + } + else { + emitTypeWithNewGetSymbolAccessibilityDiangostic(node.constraint, getTypeParameterConstraintVisibilityError); + } + } + + function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { // Type parameter constraints are named by user so we should always be able to name it var diagnosticMessage: DiagnosticMessage; switch (node.parent.kind) { @@ -2845,17 +3011,6 @@ module ts { typeName: node.name }; } - - increaseIndent(); - emitJsDocComments(node); - decreaseIndent(); - emitSourceTextOfNode(node.name); - // If there is constraint present and this is not a type parameter of the private method emit the constraint - if (node.constraint && (node.parent.kind !== SyntaxKind.Method || !(node.parent.flags & NodeFlags.Private))) { - write(" extends "); - getSymbolVisibilityDiagnosticMessage = getTypeParameterConstraintVisibilityError; - resolver.writeTypeAtLocation(node.constraint, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); - } } if (typeParameters) { @@ -2872,10 +3027,9 @@ module ts { } function emitTypeOfTypeReference(node: Node) { - getSymbolVisibilityDiagnosticMessage = getHeritageClauseVisibilityError; - resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.WriteArrayAsGenericType | TypeFormatFlags.UseTypeOfFunction, writer); + emitTypeWithNewGetSymbolAccessibilityDiangostic(node, getHeritageClauseVisibilityError); - function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { + function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { var diagnosticMessage: DiagnosticMessage; // Heritage clause is written by user so it can always be named if (node.parent.kind === SyntaxKind.ClassDeclaration) { @@ -2926,9 +3080,9 @@ module ts { if (resolver.isDeclarationVisible(node)) { emitJsDocComments(node); - emitDeclarationFlags(node); + emitModuleElementDeclarationFlags(node); write("class "); - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); var prevEnclosingDeclaration = enclosingDeclaration; enclosingDeclaration = node; emitTypeParameters(node.typeParameters); @@ -2951,9 +3105,9 @@ module ts { function emitInterfaceDeclaration(node: InterfaceDeclaration) { if (resolver.isDeclarationVisible(node)) { emitJsDocComments(node); - emitDeclarationFlags(node); + emitModuleElementDeclarationFlags(node); write("interface "); - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); var prevEnclosingDeclaration = enclosingDeclaration; enclosingDeclaration = node; emitTypeParameters(node.typeParameters); @@ -2971,7 +3125,7 @@ module ts { function emitPropertyDeclaration(node: PropertyDeclaration) { emitJsDocComments(node); - emitDeclarationFlags(node); + emitClassMemberDeclarationFlags(node); emitVariableDeclaration(node); write(";"); writeLine(); @@ -2982,19 +3136,20 @@ module ts { // If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted // so there is no check needed to see if declaration is visible if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) { - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); // If optional property emit ? if (node.kind === SyntaxKind.Property && (node.flags & NodeFlags.QuestionMark)) { write("?"); } - if (!(node.flags & NodeFlags.Private)) { - write(": "); - getSymbolVisibilityDiagnosticMessage = getVariableDeclarationTypeVisibilityError; - resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + if (node.kind === SyntaxKind.Property && node.parent.kind === SyntaxKind.TypeLiteral) { + emitTypeOfVariableDeclarationFromTypeLiteral(node); + } + else if (!(node.flags & NodeFlags.Private)) { + writeTypeAtLocation(node, node.type, getVariableDeclarationTypeVisibilityError); } } - function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { + function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { var diagnosticMessage: DiagnosticMessage; if (node.kind === SyntaxKind.VariableDeclaration) { diagnosticMessage = symbolAccesibilityResult.errorModuleName ? @@ -3036,11 +3191,21 @@ module ts { } } + function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableDeclaration) { + // if this is property of type literal, + // or is parameter of method/call/construct/index signature of type literal + // emit only if type is specified + if (node.type) { + write(": "); + emitType(node.type); + } + } + function emitVariableStatement(node: VariableStatement) { var hasDeclarationWithEmit = forEach(node.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration)); if (hasDeclarationWithEmit) { emitJsDocComments(node); - emitDeclarationFlags(node); + emitModuleElementDeclarationFlags(node); if (node.flags & NodeFlags.Let) { write("let "); } @@ -3061,22 +3226,38 @@ module ts { if (node === accessors.firstAccessor) { emitJsDocComments(accessors.getAccessor); emitJsDocComments(accessors.setAccessor); - emitDeclarationFlags(node); - emitSourceTextOfNode(node.name); + emitClassMemberDeclarationFlags(node); + writeTextOfNode(node.name); if (!(node.flags & NodeFlags.Private)) { - write(": "); - getSymbolVisibilityDiagnosticMessage = getAccessorDeclarationTypeVisibilityError; - resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + var accessorWithTypeAnnotation: AccessorDeclaration = node; + var type = getTypeAnnotationFromAccessor(node); + if (!type) { + // couldn't get type for the first accessor, try the another one + var anotherAccessor = node.kind === SyntaxKind.GetAccessor ? accessors.setAccessor : accessors.getAccessor; + type = getTypeAnnotationFromAccessor(anotherAccessor); + if (type) { + accessorWithTypeAnnotation = anotherAccessor; + } + } + writeTypeAtLocation(node, type, getAccessorDeclarationTypeVisibilityError); } write(";"); writeLine(); } - function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { + function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode { + if (accessor) { + return accessor.kind === SyntaxKind.GetAccessor ? + accessor.type : // Getter - return type + accessor.parameters[0].type; // Setter parameter type + } + } + + function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { var diagnosticMessage: DiagnosticMessage; - if (node.kind === SyntaxKind.SetAccessor) { + if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) { // Setters have to have type named and cannot infer it so, the type should always be named - if (node.parent.flags & NodeFlags.Static) { + if (accessorWithTypeAnnotation.parent.flags & NodeFlags.Static) { diagnosticMessage = symbolAccesibilityResult.errorModuleName ? Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 : Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1; @@ -3088,13 +3269,13 @@ module ts { } return { diagnosticMessage: diagnosticMessage, - errorNode: node.parameters[0], + errorNode: accessorWithTypeAnnotation.parameters[0], // TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name - typeName: node.name + typeName: accessorWithTypeAnnotation.name }; } else { - if (node.flags & NodeFlags.Static) { + if (accessorWithTypeAnnotation.flags & NodeFlags.Static) { diagnosticMessage = symbolAccesibilityResult.errorModuleName ? symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : @@ -3110,7 +3291,7 @@ module ts { } return { diagnosticMessage: diagnosticMessage, - errorNode: node.name, + errorNode: accessorWithTypeAnnotation.name, typeName: undefined }; } @@ -3123,16 +3304,21 @@ module ts { if ((node.kind !== SyntaxKind.FunctionDeclaration || resolver.isDeclarationVisible(node)) && !resolver.isImplementationOfOverload(node)) { emitJsDocComments(node); - emitDeclarationFlags(node); + if (node.kind === SyntaxKind.FunctionDeclaration) { + emitModuleElementDeclarationFlags(node); + } + else if (node.kind === SyntaxKind.Method) { + emitClassMemberDeclarationFlags(node); + } if (node.kind === SyntaxKind.FunctionDeclaration) { write("function "); - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); } else if (node.kind === SyntaxKind.Constructor) { write("constructor"); } else { - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); if (node.flags & NodeFlags.QuestionMark) { write("?"); } @@ -3141,13 +3327,13 @@ module ts { } } - function emitConstructSignatureDeclaration(node: SignatureDeclaration) { + function emitConstructSignatureDeclaration(node: SignatureDeclaration, arrowStyle?: boolean) { emitJsDocComments(node); write("new "); - emitSignatureDeclaration(node); + emitSignatureDeclaration(node, arrowStyle); } - function emitSignatureDeclaration(node: SignatureDeclaration) { + function emitSignatureDeclaration(node: SignatureDeclaration, arrowStyle?: boolean) { if (node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.IndexSignature) { // Only index and call signatures are emitted directly, so emit their js doc comments, rest will do that in their own functions emitJsDocComments(node); @@ -3160,6 +3346,9 @@ module ts { write("("); } + var prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + // Parameters emitCommaList(node.parameters, emitParameterDeclaration); @@ -3171,15 +3360,25 @@ module ts { } // If this is not a constructor and is not private, emit the return type - if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) { - write(": "); - getSymbolVisibilityDiagnosticMessage = getReturnTypeVisibilityError; - resolver.writeReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + if (node.parent.kind === SyntaxKind.TypeLiteral) { + // Emit type literal signature return type only if specified + if (node.type) { + write(arrowStyle ? " => " : ": "); + emitType(node.type); + } + } + else if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) { + writeReturnTypeAtSignature(node, getReturnTypeVisibilityError); } - write(";"); - writeLine(); - function getReturnTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { + enclosingDeclaration = prevEnclosingDeclaration; + + if (!arrowStyle) { + write(";"); + writeLine(); + } + + function getReturnTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { var diagnosticMessage: DiagnosticMessage; switch (node.kind) { case SyntaxKind.ConstructSignature: @@ -3251,19 +3450,20 @@ module ts { if (node.flags & NodeFlags.Rest) { write("..."); } - emitSourceTextOfNode(node.name); + writeTextOfNode(node.name); if (node.initializer || (node.flags & NodeFlags.QuestionMark)) { write("?"); } decreaseIndent(); - if (!(node.parent.flags & NodeFlags.Private)) { - write(": "); - getSymbolVisibilityDiagnosticMessage = getParameterDeclarationTypeVisibilityError; - resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + if (node.parent.parent.kind === SyntaxKind.TypeLiteral) { + emitTypeOfVariableDeclarationFromTypeLiteral(node); + } + else if (!(node.parent.flags & NodeFlags.Private)) { + writeTypeAtLocation(node, node.type, getParameterDeclarationTypeVisibilityError); } - function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) { + function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic { var diagnosticMessage: DiagnosticMessage; switch (node.parent.kind) { case SyntaxKind.Constructor: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 020b6432c7f..1ef50051ec3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -789,11 +789,14 @@ module ts { CannotBeNamed } - export interface SymbolAccessiblityResult { + export interface SymbolVisibilityResult { accessibility: SymbolAccessibility; + aliasesToMakeVisible?: ImportDeclaration[]; // aliases that need to have this symbol visible + } + + export interface SymbolAccessiblityResult extends SymbolVisibilityResult { errorSymbolName?: string // Optional symbol name that results in error errorModuleName?: string // If the symbol is not visible from module, module's name - aliasesToMakeVisible?: ImportDeclaration[]; // aliases that need to have this symbol visible } export interface EmitResolver { @@ -811,7 +814,7 @@ module ts { writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult; - isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult; + isEntityNameVisible(entityName: EntityName, enclosingDeclaration: Node): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant getConstantValue(node: PropertyAccess | IndexedAccess): number; hasEarlyErrors(sourceFile?: SourceFile): boolean;