Skip to content

Commit b665323

Browse files
Make the emitter no longer depend on the Program.
This breaks layering. Also, it means the emitter depends on too large a surface area. Now the emitter declares exactly what it needs, and only gets that.
1 parent 96c3c90 commit b665323

9 files changed

Lines changed: 73 additions & 65 deletions

File tree

src/compiler/checker.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ module ts {
2323
var emitResolver = createResolver();
2424

2525
var checker: TypeChecker = {
26-
getProgram: () => program,
2726
getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"),
2827
getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"),
2928
getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"),
@@ -9549,7 +9548,6 @@ module ts {
95499548

95509549
function createResolver(): EmitResolver {
95519550
return {
9552-
getProgram: () => program,
95539551
getLocalNameOfContainer,
95549552
getExpressionNamePrefix,
95559553
getExportAssignmentName,

src/compiler/emitter.ts

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -312,17 +312,17 @@ module ts {
312312
};
313313
}
314314

315-
function getSourceFilePathInNewDir(sourceFile: SourceFile, program: Program, newDirPath: string) {
316-
var compilerHost = program.getCompilerHost();
315+
function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
316+
var compilerHost = host.getCompilerHost();
317317
var sourceFilePath = getNormalizedAbsolutePath(sourceFile.filename, compilerHost.getCurrentDirectory());
318-
sourceFilePath = sourceFilePath.replace(program.getCommonSourceDirectory(), "");
318+
sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), "");
319319
return combinePaths(newDirPath, sourceFilePath);
320320
}
321321

322-
function getOwnEmitOutputFilePath(sourceFile: SourceFile, program: Program, extension: string){
323-
var compilerOptions = program.getCompilerOptions();
322+
function getOwnEmitOutputFilePath(sourceFile: SourceFile, host: EmitHost, extension: string){
323+
var compilerOptions = host.getCompilerOptions();
324324
if (compilerOptions.outDir) {
325-
var emitOutputFilePathWithoutExtension = removeFileExtension(getSourceFilePathInNewDir(sourceFile, program, compilerOptions.outDir));
325+
var emitOutputFilePathWithoutExtension = removeFileExtension(getSourceFilePathInNewDir(sourceFile, host, compilerOptions.outDir));
326326
}
327327
else {
328328
var emitOutputFilePathWithoutExtension = removeFileExtension(sourceFile.filename);
@@ -337,10 +337,10 @@ module ts {
337337
});
338338
}
339339

340-
function emitDeclarations(program: Program, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit {
341-
var newLine = program.getCompilerHost().getNewLine();
342-
var compilerOptions = program.getCompilerOptions();
343-
var compilerHost = program.getCompilerHost();
340+
function emitDeclarations(host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit {
341+
var newLine = host.getCompilerHost().getNewLine();
342+
var compilerOptions = host.getCompilerOptions();
343+
var compilerHost = host.getCompilerHost();
344344

345345
var write: (s: string) => void;
346346
var writeLine: () => void;
@@ -1396,8 +1396,8 @@ module ts {
13961396
var declFileName = referencedFile.flags & NodeFlags.DeclarationFile
13971397
? referencedFile.filename // Declaration file, use declaration file name
13981398
: shouldEmitToOwnFile(referencedFile, compilerOptions)
1399-
? getOwnEmitOutputFilePath(referencedFile, program, ".d.ts") // Own output file so get the .d.ts file
1400-
: removeFileExtension(compilerOptions.out) + ".d.ts";// Global out file
1399+
? getOwnEmitOutputFilePath(referencedFile, host, ".d.ts") // Own output file so get the .d.ts file
1400+
: removeFileExtension(compilerOptions.out) + ".d.ts";// Global out file
14011401

14021402
declFileName = getRelativePathToDirectoryOrUrl(
14031403
getDirectoryPath(normalizeSlashes(jsFilePath)),
@@ -1414,7 +1414,7 @@ module ts {
14141414
if (!compilerOptions.noResolve) {
14151415
var addedGlobalFileReference = false;
14161416
forEach(root.referencedFiles, fileReference => {
1417-
var referencedFile = tryResolveScriptReference(program, root, fileReference);
1417+
var referencedFile = tryResolveScriptReference(host, root, fileReference);
14181418

14191419
// All the references that are not going to be part of same file
14201420
if (referencedFile && ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference
@@ -1434,12 +1434,12 @@ module ts {
14341434
else {
14351435
// Emit references corresponding to this file
14361436
var emittedReferencedFiles: SourceFile[] = [];
1437-
forEach(program.getSourceFiles(), sourceFile => {
1437+
forEach(host.getSourceFiles(), sourceFile => {
14381438
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
14391439
// Check what references need to be added
14401440
if (!compilerOptions.noResolve) {
14411441
forEach(sourceFile.referencedFiles, fileReference => {
1442-
var referencedFile = tryResolveScriptReference(program, sourceFile, fileReference);
1442+
var referencedFile = tryResolveScriptReference(host, sourceFile, fileReference);
14431443

14441444
// If the reference file is a declaration file or an external module, emit that reference
14451445
if (referencedFile && (isExternalModuleOrDeclarationFile(referencedFile) &&
@@ -1472,13 +1472,13 @@ module ts {
14721472
}
14731473

14741474
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compilerOnSave feature
1475-
export function emitFiles(resolver: EmitResolver, targetSourceFile?: SourceFile): EmitResult {
1476-
var program = resolver.getProgram();
1477-
var compilerHost = program.getCompilerHost();
1478-
var compilerOptions = program.getCompilerOptions();
1475+
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile?: SourceFile): EmitResult {
1476+
// var program = resolver.getProgram();
1477+
var compilerHost = host.getCompilerHost();
1478+
var compilerOptions = host.getCompilerOptions();
14791479
var sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined;
14801480
var diagnostics: Diagnostic[] = [];
1481-
var newLine = program.getCompilerHost().getNewLine();
1481+
var newLine = compilerHost.getNewLine();
14821482

14831483
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
14841484
var writer = createTextWriter(newLine);
@@ -1700,7 +1700,7 @@ module ts {
17001700
// Add the file to tsFilePaths
17011701
// If sourceroot option: Use the relative path corresponding to the common directory path
17021702
// otherwise source locations relative to map file location
1703-
var sourcesDirectoryPath = compilerOptions.sourceRoot ? program.getCommonSourceDirectory() : sourceMapDir;
1703+
var sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir;
17041704

17051705
sourceMapData.sourceMapSources.push(getRelativePathToDirectoryOrUrl(sourcesDirectoryPath,
17061706
node.filename,
@@ -1840,12 +1840,12 @@ module ts {
18401840
if (root) { // emitting single module file
18411841
// For modules or multiple emit files the mapRoot will have directory structure like the sources
18421842
// So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
1843-
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(root, program, sourceMapDir));
1843+
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(root, host, sourceMapDir));
18441844
}
18451845

18461846
if (!isRootedDiskPath(sourceMapDir) && !isUrl(sourceMapDir)) {
18471847
// The relative paths are relative to the common directory
1848-
sourceMapDir = combinePaths(program.getCommonSourceDirectory(), sourceMapDir);
1848+
sourceMapDir = combinePaths(host.getCommonSourceDirectory(), sourceMapDir);
18491849
sourceMapData.jsSourceMappingURL = getRelativePathToDirectoryOrUrl(
18501850
getDirectoryPath(normalizePath(jsFilePath)), // get the relative sourceMapDir path based on jsFilePath
18511851
combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL), // this is where user expects to see sourceMap
@@ -4101,7 +4101,7 @@ module ts {
41014101
emit(root);
41024102
}
41034103
else {
4104-
forEach(program.getSourceFiles(), sourceFile => {
4104+
forEach(host.getSourceFiles(), sourceFile => {
41054105
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
41064106
emit(sourceFile);
41074107
}
@@ -4113,7 +4113,7 @@ module ts {
41134113
}
41144114

41154115
function writeDeclarationFile(jsFilePath: string, sourceFile: SourceFile) {
4116-
var emitDeclarationResult = emitDeclarations(program, resolver, diagnostics, jsFilePath, sourceFile);
4116+
var emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, jsFilePath, sourceFile);
41174117
// TODO(shkamat): Should we not write any declaration file if any of them can produce error,
41184118
// or should we just not write this file like we are doing now
41194119
if (!emitDeclarationResult.reportedDeclarationError) {
@@ -4140,9 +4140,9 @@ module ts {
41404140
hasSemanticErrors = resolver.hasSemanticErrors();
41414141
isEmitBlocked = resolver.isEmitBlocked();
41424142

4143-
forEach(program.getSourceFiles(), sourceFile => {
4143+
forEach(host.getSourceFiles(), sourceFile => {
41444144
if (shouldEmitToOwnFile(sourceFile, compilerOptions)) {
4145-
var jsFilePath = getOwnEmitOutputFilePath(sourceFile, program, ".js");
4145+
var jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, ".js");
41464146
emitFile(jsFilePath, sourceFile);
41474147
}
41484148
});
@@ -4158,13 +4158,13 @@ module ts {
41584158
hasSemanticErrors = resolver.hasSemanticErrors(targetSourceFile);
41594159
isEmitBlocked = resolver.isEmitBlocked(targetSourceFile);
41604160

4161-
var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, program, ".js");
4161+
var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js");
41624162
emitFile(jsFilePath, targetSourceFile);
41634163
}
41644164
else if (!isDeclarationFile(targetSourceFile) && compilerOptions.out) {
41654165
// Otherwise, if --out is specified and targetSourceFile is not a declaration file,
41664166
// Emit all, non-external-module file, into one single output file
4167-
forEach(program.getSourceFiles(), sourceFile => {
4167+
forEach(host.getSourceFiles(), sourceFile => {
41684168
if (!shouldEmitToOwnFile(sourceFile, compilerOptions)) {
41694169
hasSemanticErrors = hasSemanticErrors || resolver.hasSemanticErrors(sourceFile);
41704170
isEmitBlocked = isEmitBlocked || resolver.isEmitBlocked(sourceFile);

src/compiler/program.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,6 @@ module ts {
9292
var diagnosticsProducingTypeChecker: TypeChecker;
9393
var noDiagnosticsTypeChecker: TypeChecker;
9494

95-
function getTypeChecker(produceDiagnostics: boolean) {
96-
if (produceDiagnostics) {
97-
return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, produceDiagnostics));
98-
}
99-
else {
100-
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, produceDiagnostics));
101-
}
102-
}
103-
10495
program = {
10596
getSourceFile: getSourceFile,
10697
getSourceFiles: () => files,
@@ -115,6 +106,15 @@ module ts {
115106
};
116107
return program;
117108

109+
function getTypeChecker(produceDiagnostics: boolean) {
110+
if (produceDiagnostics) {
111+
return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, produceDiagnostics));
112+
}
113+
else {
114+
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, produceDiagnostics));
115+
}
116+
}
117+
118118
function getDeclarationDiagnostics(targetSourceFile: SourceFile): Diagnostic[]{
119119
var fullTypeChecker = getTypeChecker(/*produceDiagnostics:*/true);
120120
fullTypeChecker.getDiagnostics(targetSourceFile);
@@ -124,7 +124,7 @@ module ts {
124124

125125
function invokeEmitter(targetSourceFile?: SourceFile) {
126126
var resolver = getTypeChecker(/*produceDiagnostics:*/true).getEmitResolver();
127-
return emitFiles(resolver, targetSourceFile);
127+
return emitFiles(resolver, program, targetSourceFile);
128128
}
129129

130130
function getSourceFile(filename: string) {

src/compiler/types.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ module ts {
246246
EnumMember,
247247
// Top-level nodes
248248
SourceFile,
249-
Program,
250249

251250
// Synthesized list
252251
SyntaxList,
@@ -968,7 +967,6 @@ module ts {
968967
}
969968

970969
export interface TypeChecker {
971-
getProgram(): Program;
972970
getEmitResolver(): EmitResolver;
973971
getDiagnostics(sourceFile?: SourceFile): Diagnostic[];
974972
getGlobalDiagnostics(): Diagnostic[];
@@ -1076,8 +1074,15 @@ module ts {
10761074
errorModuleName?: string // If the symbol is not visible from module, module's name
10771075
}
10781076

1077+
export interface EmitHost {
1078+
getSourceFile(filename: string): SourceFile;
1079+
getSourceFiles(): SourceFile[];
1080+
getCompilerHost(): CompilerHost;
1081+
getCompilerOptions(): CompilerOptions;
1082+
getCommonSourceDirectory(): string;
1083+
}
1084+
10791085
export interface EmitResolver {
1080-
getProgram(): Program;
10811086
getLocalNameOfContainer(container: ModuleDeclaration | EnumDeclaration): string;
10821087
getExpressionNamePrefix(node: Identifier): string;
10831088
getExportAssignmentName(node: SourceFile): string;

src/compiler/utilities.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -636,11 +636,11 @@ module ts {
636636
return undefined;
637637
}
638638

639-
export function tryResolveScriptReference(program: Program, sourceFile: SourceFile, reference: FileReference) {
640-
if (!program.getCompilerOptions().noResolve) {
639+
export function tryResolveScriptReference(host: EmitHost, sourceFile: SourceFile, reference: FileReference) {
640+
if (!host.getCompilerOptions().noResolve) {
641641
var referenceFileName = isRootedDiskPath(reference.filename) ? reference.filename : combinePaths(getDirectoryPath(sourceFile.filename), reference.filename);
642-
referenceFileName = getNormalizedAbsolutePath(referenceFileName, program.getCompilerHost().getCurrentDirectory());
643-
return program.getSourceFile(referenceFileName);
642+
referenceFileName = getNormalizedAbsolutePath(referenceFileName, host.getCompilerHost().getCurrentDirectory());
643+
return host.getSourceFile(referenceFileName);
644644
}
645645
}
646646

src/harness/compilerRunner.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class CompilerBaselineRunner extends RunnerBase {
5353
var rootDir: string;
5454

5555
var result: Harness.Compiler.CompilerResult;
56-
var checker: ts.TypeChecker;
56+
var program: ts.Program;
5757
var options: ts.CompilerOptions;
5858
// equivalent to the files that will be passed on the command line
5959
var toBeCompiled: { unitName: string; content: string }[];
@@ -97,10 +97,10 @@ class CompilerBaselineRunner extends RunnerBase {
9797
});
9898
}
9999

100-
options = harnessCompiler.compileFiles(toBeCompiled, otherFiles, function (compileResult, _checker) {
100+
options = harnessCompiler.compileFiles(toBeCompiled, otherFiles, function (compileResult, _program) {
101101
result = compileResult;
102-
// The checker will be used by typeWriter
103-
checker = _checker;
102+
// The program will be used by typeWriter
103+
program = _program;
104104
}, function (settings) {
105105
harnessCompiler.setCompilerSettings(tcSettings);
106106
});
@@ -138,7 +138,7 @@ class CompilerBaselineRunner extends RunnerBase {
138138
lastUnit = undefined;
139139
rootDir = undefined;
140140
result = undefined;
141-
checker = undefined;
141+
program = undefined;
142142
options = undefined;
143143
toBeCompiled = undefined;
144144
otherFiles = undefined;
@@ -267,10 +267,10 @@ class CompilerBaselineRunner extends RunnerBase {
267267
// NEWTODO: Type baselines
268268
if (result.errors.length === 0) {
269269
Harness.Baseline.runBaseline('Correct expression types for ' + fileName, justName.replace(/\.ts/, '.types'), () => {
270-
var allFiles = toBeCompiled.concat(otherFiles).filter(file => !!checker.getProgram().getSourceFile(file.unitName));
270+
var allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
271271
var typeLines: string[] = [];
272272
var typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
273-
var walker = new TypeWriterWalker(checker);
273+
var walker = new TypeWriterWalker(program);
274274
allFiles.forEach(file => {
275275
var codeLines = file.content.split('\n');
276276
walker.getTypes(file.unitName).forEach(result => {

src/harness/harness.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ module Harness {
885885

886886
public compileFiles(inputFiles: { unitName: string; content: string }[],
887887
otherFiles: { unitName: string; content: string }[],
888-
onComplete: (result: CompilerResult, checker: ts.TypeChecker) => void,
888+
onComplete: (result: CompilerResult, program: ts.Program) => void,
889889
settingsCallback?: (settings: ts.CompilerOptions) => void,
890890
options?: ts.CompilerOptions) {
891891

@@ -1062,7 +1062,7 @@ module Harness {
10621062
this.lastErrors = errors;
10631063

10641064
var result = new CompilerResult(fileOutputs, errors, program, ts.sys.getCurrentDirectory(), emitResult ? emitResult.sourceMaps : undefined);
1065-
onComplete(result, checker);
1065+
onComplete(result, program);
10661066

10671067
// reset what newline means in case the last test changed it
10681068
ts.sys.newLine = '\r\n';

0 commit comments

Comments
 (0)