Skip to content

Commit 6ef41a7

Browse files
author
Yui T
committed
Move checking semantic diagnostics into emitFiles function rather than
getEmitOutput
1 parent 537f55c commit 6ef41a7

File tree

6 files changed

+67
-47
lines changed

6 files changed

+67
-47
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7181,6 +7181,11 @@ module ts {
71817181
return target !== unknownSymbol && ((target.flags & SymbolFlags.Value) !== 0);
71827182
}
71837183

7184+
function hasSemanticErrors() {
7185+
// Return true if there is any semantic error in a file or globally
7186+
return (getDiagnostics().length > 0) || (getGlobalDiagnostics().length > 0);
7187+
}
7188+
71847189
function shouldEmitDeclarations() {
71857190
// If the declaration emit and there are no errors being reported in program or by checker
71867191
// declarations can be emitted
@@ -7258,6 +7263,7 @@ module ts {
72587263
getNodeCheckFlags: getNodeCheckFlags,
72597264
getEnumMemberValue: getEnumMemberValue,
72607265
isTopLevelValueImportedViaEntityName: isTopLevelValueImportedViaEntityName,
7266+
hasSemanticErrors: hasSemanticErrors,
72617267
shouldEmitDeclarations: shouldEmitDeclarations,
72627268
isDeclarationVisible: isDeclarationVisible,
72637269
isImplementationOfOverload: isImplementationOfOverload,

src/compiler/emitter.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ module ts {
4848
}
4949

5050
function getOwnEmitOutputFilePath(sourceFile: SourceFile, extension: string) {
51-
if (program.getCompilerOptions().outDir) {
52-
var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(getSourceFilePathInNewDir(program.getCompilerOptions().outDir, sourceFile));
51+
if (compilerOptions.outDir) {
52+
var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(getSourceFilePathInNewDir(compilerOptions.outDir, sourceFile));
5353
}
5454
else {
5555
var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(sourceFile.filename);
@@ -3183,7 +3183,27 @@ module ts {
31833183
diagnostics.sort(compareDiagnostics);
31843184
diagnostics = deduplicateSortedDiagnostics(diagnostics);
31853185

3186+
var returnCode = EmitReturnStatus.Succeeded;
3187+
3188+
// Check if there is any diagnostic in an error category; if so, there is an emitter error
3189+
var hasEmitterError = forEach(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error);
3190+
3191+
if (resolver.hasSemanticErrors() && !compilerOptions.declaration) {
3192+
// There is an semantic errror when output javascript file
3193+
// Output JS file with semantic error
3194+
returnCode = EmitReturnStatus.JSGeneratedWithSemanticErrors;
3195+
}
3196+
else if (resolver.hasSemanticErrors() && compilerOptions.declaration) {
3197+
// There is an semantic errror when output javascript and declaration file
3198+
// Output JS file with semantic error, not output declaration file
3199+
returnCode = EmitReturnStatus.DeclarationGenerationSkipped;
3200+
}
3201+
else if (hasEmitterError) {
3202+
returnCode = EmitReturnStatus.EmitErrorsEncountered;
3203+
}
3204+
31863205
return {
3206+
emitResultStatus: returnCode,
31873207
errors: diagnostics,
31883208
sourceMaps: sourceMapDataList
31893209
};

src/compiler/types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,17 @@ module ts {
588588
sourceMapDecodedMappings: SourceMapSpan[];
589589
}
590590

591+
// Return code used by getEmitOutput function to indicate status of the function
592+
export enum EmitReturnStatus {
593+
Succeeded = 0, // All outputs generated as requested (.js, .map, .d.ts), no errors reported
594+
AllOutputGenerationSkipped = 1, // No .js generated because of syntax errors, or compiler options errors, nothing generated
595+
JSGeneratedWithSemanticErrors = 2, // .js and .map generated with semantic errors
596+
DeclarationGenerationSkipped = 3, // .d.ts generation skipped because of semantic errors or declaration emitter specific errors; Output .js with semantic errors
597+
EmitErrorsEncountered = 4 // Emitter errors occured during emitting process
598+
}
599+
591600
export interface EmitResult {
601+
emitResultStatus: EmitReturnStatus;
592602
errors: Diagnostic[];
593603
sourceMaps: SourceMapData[]; // Array of sourceMapData if compiler emitted sourcemaps
594604
}
@@ -660,6 +670,7 @@ module ts {
660670
isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean;
661671
getNodeCheckFlags(node: Node): NodeCheckFlags;
662672
getEnumMemberValue(node: EnumMember): number;
673+
hasSemanticErrors(): boolean;
663674
shouldEmitDeclarations(): boolean;
664675
isDeclarationVisible(node: Declaration): boolean;
665676
isImplementationOfOverload(node: FunctionDeclaration): boolean;

src/harness/fourslash.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ module FourSlash {
458458
}
459459
}
460460

461-
public verifyEmitOutput(state: ts.EmitOutputResult, filename?: string) {
461+
public verifyEmitOutput(state: ts.EmitReturnStatus, filename?: string) {
462462
if (this.enableDeclaration) {
463463
this.languageServiceShimHost.setCompilationSettings({ generateDeclarationFiles: true });
464464
}
@@ -474,8 +474,8 @@ module FourSlash {
474474

475475
var emit = this.languageService.getEmitOutput(this.activeFile.fileName);
476476

477-
if (emit.emitOutputResult !== state) {
478-
throw new Error("Expected emitOutputResult '" + state + "', but actual emitOutputResult '" + emit.emitOutputResult + "'");
477+
if (emit.emitOutputStatus !== state) {
478+
throw new Error("Expected emitOutputResult '" + state + "', but actual emitOutputResult '" + emit.emitOutputStatus + "'");
479479
}
480480

481481
var passed = true;

src/services/services.ts

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -663,16 +663,9 @@ module ts {
663663
docComment: string;
664664
}
665665

666-
export enum EmitOutputResult {
667-
Succeeded,
668-
FailedBecauseOfSyntaxErrors,
669-
FailedBecauseOfCompilerOptionsErrors,
670-
FailedToGenerateDeclarationsBecauseOfSemanticErrors
671-
}
672-
673666
export interface EmitOutput {
674667
outputFiles: OutputFile[];
675-
emitOutputResult: EmitOutputResult;
668+
emitOutputStatus: EmitReturnStatus;
676669
}
677670

678671
export enum OutputFileType {
@@ -2846,56 +2839,43 @@ module ts {
28462839
function getEmitOutput(filename: string): EmitOutput {
28472840
synchronizeHostData();
28482841
filename = TypeScript.switchToForwardSlashes(filename);
2849-
var sourceFile = getSourceFile(filename);
2842+
var sourceFile = program.getSourceFile(filename);
28502843
var compilerOptions = program.getCompilerOptions();
2851-
var emitToSingleFile = ts.shouldEmitToOwnFile(program.getSourceFile(filename), compilerOptions);
2844+
var emitToSingleFile = ts.shouldEmitToOwnFile(sourceFile, compilerOptions);
28522845
var emitDeclaration = compilerOptions.declaration;
2853-
var emitResult: EmitOutput = {
2846+
var emitOutput: EmitOutput = {
28542847
outputFiles: [],
2855-
emitOutputResult: undefined,
2848+
emitOutputStatus: undefined,
28562849
};
28572850

28582851
// Initialize writer for CompilerHost.writeFile
28592852
writer = function (fileName: string, data: string, writeByteOrderMark: boolean) {
2860-
var outputFile: OutputFile = {
2853+
emitOutput.outputFiles.push({
28612854
name: fileName,
28622855
writeByteOrderMark: writeByteOrderMark,
28632856
text: data
2864-
}
2865-
emitResult.outputFiles.push(outputFile);
2857+
});
28662858
}
28672859

28682860
var syntacticDiagnostics = emitToSingleFile
28692861
? program.getDiagnostics(sourceFile)
28702862
: program.getDiagnostics();
2871-
program.getGlobalDiagnostics();
2863+
var globalSyntacticDiagnostics = program.getGlobalDiagnostics();
28722864

28732865
// If there is any syntactic error, terminate the process
28742866
if (containErrors(syntacticDiagnostics)) {
2875-
emitResult.emitOutputResult = EmitOutputResult.FailedBecauseOfSyntaxErrors;
2876-
return emitResult;
2867+
emitOutput.emitOutputStatus = EmitReturnStatus.AllOutputGenerationSkipped;
2868+
return emitOutput;
28772869
}
28782870

28792871
// Perform semantic and force a type check before emit to ensure that all symbols are updated
2880-
var semanticDiagnostics = emitToSingleFile
2881-
? getFullTypeCheckChecker().getDiagnostics(getSourceFile(filename).getSourceFile())
2882-
: getFullTypeCheckChecker().getDiagnostics();
2883-
getFullTypeCheckChecker().getGlobalDiagnostics();
2884-
var emitOutput = getFullTypeCheckChecker().emitFiles();
2885-
2886-
if (emitDeclaration && containErrors(semanticDiagnostics)) {
2887-
emitResult.emitOutputResult = EmitOutputResult.FailedToGenerateDeclarationsBecauseOfSemanticErrors;
2888-
}
2889-
else if (emitDeclaration && containErrors(emitOutput.errors)) {
2890-
emitResult.emitOutputResult = EmitOutputResult.FailedToGenerateDeclarationsBecauseOfSemanticErrors;
2891-
}
2892-
else {
2893-
emitResult.emitOutputResult = EmitOutputResult.Succeeded;
2894-
}
2872+
// EmitFiles will report if there is an error from TypeChecker and Emitter
2873+
var emitFilesResult = getFullTypeCheckChecker().emitFiles();
2874+
emitOutput.emitOutputStatus = emitFilesResult.emitResultStatus;
28952875

2896-
// Reset writer back to underfined to make sure that we produce an error message if CompilerHost.writeFile method is called when we are not in an emitting stage
2876+
// Reset writer back to underfined to make sure that we produce an error message if CompilerHost.writeFile method is called when we are not in getEmitOutput
28972877
this.writer = undefined;
2898-
return emitResult;
2878+
return emitOutput;
28992879
}
29002880

29012881
/// Syntactic features

tests/cases/fourslash/fourslash.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,17 @@ enum TypingFidelity {
4444
High = FourSlash.TypingFidelity.High
4545
}
4646

47-
// We have to duplicate EmitOutputResult from Services.ts to expose the enum to getEmitOutput testcases in fourslah
48-
enum EmitOutputResult {
49-
Succeeded,
50-
FailedBecauseOfSyntaxErrors,
51-
FailedBecauseOfCompilerOptionsErrors,
52-
FailedToGenerateDeclarationsBecauseOfSemanticErrors
47+
// Return code used by getEmitOutput function to indicate status of the function
48+
// It is a duplicate of the one in types.ts to expose it to testcases in fourslash
49+
enum EmitReturnStatus {
50+
Succeeded = 0, // All outputs generated as requested (.js, .map, .d.ts), no errors reported
51+
AllOutputGenerationSkipped = 1, // No .js generated because of syntax errors, or compiler options errors, nothing generated
52+
JSGeneratedWithSemanticErrors = 2, // .js and .map generated with semantic errors
53+
DeclarationGenerationSkipped = 3, // .d.ts generation skipped because of semantic errors or declaration emitter specific errors; Output .js with semantic errors
54+
EmitErrorsEncountered = 4 // Emitter errors occured during emitting process
5355
}
5456

57+
5558
module FourSlashInterface {
5659
declare var FourSlash;
5760

@@ -263,7 +266,7 @@ module FourSlashInterface {
263266
FourSlash.currentTestState.verifyEval(expr, value);
264267
}
265268

266-
public emitOutput(expectedState: EmitOutputResult, expectedFilename?: string) {
269+
public emitOutput(expectedState: EmitReturnStatus, expectedFilename?: string) {
267270
FourSlash.currentTestState.verifyEmitOutput(expectedState, expectedFilename);
268271
}
269272

0 commit comments

Comments
 (0)