Skip to content

Commit b6d083f

Browse files
Do not publicly expose a way on a Program instance to get typecheckers with differing behavior.
Now, you can only get the non-diagnostics, pull-type-checker from the Program instance. If you want diagnostics, you simply ask the Program instance for the diagnostics you want.
1 parent 5b049fe commit b6d083f

25 files changed

Lines changed: 2145 additions & 69 deletions

src/compiler/program.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ module ts {
8888
verifyCompilerOptions();
8989
errors.sort(compareDiagnostics);
9090

91-
9291
var diagnosticsProducingTypeChecker: TypeChecker;
9392
var noDiagnosticsTypeChecker: TypeChecker;
9493
var emitHost: EmitHost;
@@ -104,10 +103,16 @@ module ts {
104103
getTypeCheckerGlobalDiagnostics,
105104
getDeclarationDiagnostics,
106105
getTypeChecker,
106+
getDiagnosticsProducingTypeChecker,
107107
getCommonSourceDirectory: () => commonSourceDirectory,
108108
emitFiles: invokeEmitter,
109109
isEmitBlocked,
110110
getCurrentDirectory: host.getCurrentDirectory,
111+
getEmitResolver: () => getDiagnosticsProducingTypeChecker().getEmitResolver(),
112+
getNodeCount: () => getDiagnosticsProducingTypeChecker().getNodeCount(),
113+
getIdentifierCount: () => getDiagnosticsProducingTypeChecker().getIdentifierCount(),
114+
getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(),
115+
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
111116
};
112117
return program;
113118

@@ -127,13 +132,8 @@ module ts {
127132
return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ true));
128133
}
129134

130-
function getTypeChecker(produceDiagnostics: boolean) {
131-
if (produceDiagnostics) {
132-
return getDiagnosticsProducingTypeChecker();
133-
}
134-
else {
135-
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, produceDiagnostics));
136-
}
135+
function getTypeChecker() {
136+
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ false));
137137
}
138138

139139
function getDeclarationDiagnostics(targetSourceFile: SourceFile): Diagnostic[]{

src/compiler/tsc.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,8 @@ module ts {
336336
exitStatus = EmitReturnStatus.AllOutputGenerationSkipped;
337337
}
338338
else {
339-
var checker = program.getTypeChecker(/*fullTypeCheckMode*/ true);
340339
var checkStart = new Date().getTime();
341-
errors = checker.getDiagnostics();
340+
errors = program.getTypeCheckerDiagnostics();
342341
if (program.isEmitBlocked()) {
343342
exitStatus = EmitReturnStatus.AllOutputGenerationSkipped;
344343
}
@@ -367,10 +366,10 @@ module ts {
367366
var memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1;
368367
reportCountStatistic("Files", program.getSourceFiles().length);
369368
reportCountStatistic("Lines", countLines(program));
370-
reportCountStatistic("Nodes", checker ? checker.getNodeCount() : 0);
371-
reportCountStatistic("Identifiers", checker ? checker.getIdentifierCount() : 0);
372-
reportCountStatistic("Symbols", checker ? checker.getSymbolCount() : 0);
373-
reportCountStatistic("Types", checker ? checker.getTypeCount() : 0);
369+
reportCountStatistic("Nodes", program.getNodeCount());
370+
reportCountStatistic("Identifiers", program.getIdentifierCount());
371+
reportCountStatistic("Symbols", program.getSymbolCount());
372+
reportCountStatistic("Types", program.getTypeCount());
374373
if (memoryUsed >= 0) {
375374
reportStatisticalValue("Memory used", Math.round(memoryUsed / 1000) + "K");
376375
}

src/compiler/types.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,7 @@ module ts {
930930
export interface Program extends ScriptReferenceHost {
931931
getSourceFiles(): SourceFile[];
932932
getCompilerHost(): CompilerHost;
933+
getEmitResolver(): EmitResolver;
933934

934935
// These will merge with the below diagnostics function in a followup checkin.
935936
getTypeCheckerDiagnostics(sourceFile?: SourceFile): Diagnostic[];
@@ -947,11 +948,20 @@ module ts {
947948
//
948949
// If 'produceDiagnostics' is false, then any calls to get diagnostics from the TypeChecker
949950
// will throw an invalid operation exception.
950-
getTypeChecker(produceDiagnostics: boolean): TypeChecker;
951+
getTypeChecker(): TypeChecker;
951952
getCommonSourceDirectory(): string;
952953

953954
emitFiles(targetSourceFile?: SourceFile): EmitResult;
954955
isEmitBlocked(sourceFile?: SourceFile): boolean;
956+
957+
// For testing purposes only. Should not be used by any other consumers (including the
958+
// language service).
959+
/* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker;
960+
961+
/* @internal */ getNodeCount(): number;
962+
/* @internal */ getIdentifierCount(): number;
963+
/* @internal */ getSymbolCount(): number;
964+
/* @internal */ getTypeCount(): number;
955965
}
956966

957967
export interface SourceMapSpan {
@@ -1000,7 +1010,6 @@ module ts {
10001010
}
10011011

10021012
export interface TypeChecker {
1003-
getEmitResolver(): EmitResolver;
10041013
getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type;
10051014
getDeclaredTypeOfSymbol(symbol: Symbol): Type;
10061015
getPropertiesOfType(type: Type): Symbol[];
@@ -1033,6 +1042,7 @@ module ts {
10331042
// Should not be called directly. Should only be accessed through the Program instance.
10341043
/* @internal */ getDiagnostics(sourceFile?: SourceFile): Diagnostic[];
10351044
/* @internal */ getGlobalDiagnostics(): Diagnostic[];
1045+
/* @internal */ getEmitResolver(): EmitResolver;
10361046

10371047
/* @internal */ getNodeCount(): number;
10381048
/* @internal */ getIdentifierCount(): number;

src/harness/compilerRunner.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,40 @@ class CompilerBaselineRunner extends RunnerBase {
256256
it('Correct type baselines for ' + fileName, () => {
257257
// NEWTODO: Type baselines
258258
if (result.errors.length === 0) {
259-
Harness.Baseline.runBaseline('Correct expression types for ' + fileName, justName.replace(/\.ts/, '.types'), () => {
259+
// The full walker simulates the types that you would get from doing a full
260+
// compile. The pull walker simulates the types you get when you just do
261+
// a type query for a random node (like how the LS would do it). Most of the
262+
// time, these will be the same. However, occasionally, they can be different.
263+
// Specifically, when the compiler internally depends on symbol IDs to order
264+
// things, then we may see different results because symbols can be created in a
265+
// different order with 'pull' operations, and thus can produce slightly differing
266+
// output.
267+
//
268+
// For example, with a full type check, we may see a type outputed as: number | string
269+
// But with a pull type check, we may see it as: string | number
270+
//
271+
// These types are equivalent, but depend on what order the compiler observed
272+
// certain parts of the program.
273+
274+
var fullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ true);
275+
var pullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ false);
276+
277+
var fullTypes = generateTypes(fullWalker);
278+
var pullTypes = generateTypes(pullWalker);
279+
280+
if (fullTypes !== pullTypes) {
281+
Harness.Baseline.runBaseline('Correct full expression types for ' + fileName, justName.replace(/\.ts/, '.types'), () => fullTypes);
282+
Harness.Baseline.runBaseline('Correct pull expression types for ' + fileName, justName.replace(/\.ts/, '.types.pull'), () => pullTypes);
283+
}
284+
else {
285+
Harness.Baseline.runBaseline('Correct expression types for ' + fileName, justName.replace(/\.ts/, '.types'), () => fullTypes);
286+
}
287+
288+
function generateTypes(walker: TypeWriterWalker): string {
260289
var allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
261290
var typeLines: string[] = [];
262291
var typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
263-
var walker = new TypeWriterWalker(program);
292+
264293
allFiles.forEach(file => {
265294
var codeLines = file.content.split('\n');
266295
walker.getTypes(file.unitName).forEach(result => {
@@ -299,7 +328,7 @@ class CompilerBaselineRunner extends RunnerBase {
299328
});
300329

301330
return typeLines.join('');
302-
});
331+
}
303332
}
304333
});
305334
});

src/harness/harness.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,8 +1081,6 @@ module Harness {
10811081
(fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }),
10821082
options.target, useCaseSensitiveFileNames, currentDirectory));
10831083

1084-
var checker = program.getTypeChecker(/*produceDiagnostics*/ true);
1085-
10861084
var isEmitBlocked = program.isEmitBlocked();
10871085

10881086
// only emit if there weren't parse errors
@@ -1092,7 +1090,7 @@ module Harness {
10921090
}
10931091

10941092
var errors: HarnessDiagnostic[] = [];
1095-
program.getDiagnostics().concat(checker.getDiagnostics()).concat(emitResult ? emitResult.diagnostics : []).forEach(err => {
1093+
program.getDiagnostics().concat(program.getTypeCheckerDiagnostics()).concat(emitResult ? emitResult.diagnostics : []).forEach(err => {
10961094
// TODO: new compiler formats errors after this point to add . and newlines so we'll just do it manually for now
10971095
errors.push(getMinimalDiagnostic(err));
10981096
});

src/harness/projectsRunner.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,7 @@ class ProjectRunner extends RunnerBase {
130130
var errors = program.getDiagnostics();
131131
var sourceMapData: ts.SourceMapData[] = null;
132132
if (!errors.length) {
133-
var checker = program.getTypeChecker(/*produceDiagnostics:*/ true);
134-
errors = checker.getDiagnostics();
133+
errors = program.getTypeCheckerDiagnostics();
135134
var emitResult = program.emitFiles();
136135
errors = ts.concatenate(errors, emitResult.diagnostics);
137136
sourceMapData = emitResult.sourceMaps;

src/harness/typeWriter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ class TypeWriterWalker {
1212

1313
private checker: ts.TypeChecker;
1414

15-
constructor(private program: ts.Program) {
15+
constructor(private program: ts.Program, fullTypeCheck: boolean) {
1616
// Consider getting both the diagnostics checker and the non-diagnostics checker to verify
1717
// they are consistent.
18-
this.checker = program.getTypeChecker(/*produceDiagnostics:*/ true);
18+
this.checker = fullTypeCheck
19+
? program.getDiagnosticsProducingTypeChecker()
20+
: program.getTypeChecker();
1921
}
2022

2123
public getTypes(fileName: string): TypeWriterResult[] {

src/services/services.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,10 +2024,6 @@ module ts {
20242024
return sourceFile;
20252025
}
20262026

2027-
function getDiagnosticsProducingTypeChecker() {
2028-
return program.getTypeChecker(/*produceDiagnostics:*/ true);
2029-
}
2030-
20312027
function getRuleProvider(options: FormatCodeOptions) {
20322028
// Ensure rules are initialized and up to date wrt to formatting options
20332029
if (!ruleProvider) {
@@ -2076,7 +2072,7 @@ module ts {
20762072
}
20772073

20782074
program = newProgram;
2079-
typeInfoResolver = program.getTypeChecker(/*produceDiagnostics*/ false);
2075+
typeInfoResolver = program.getTypeChecker();
20802076

20812077
return;
20822078

@@ -2155,7 +2151,7 @@ module ts {
21552151
*/
21562152
function cleanupSemanticCache(): void {
21572153
if (program) {
2158-
typeInfoResolver = program.getTypeChecker(/*produceDiagnostics*/ false);
2154+
typeInfoResolver = program.getTypeChecker();
21592155
}
21602156
}
21612157

@@ -4673,7 +4669,7 @@ module ts {
46734669
var emitHost = createEmitHostFromProgram(program);
46744670
emitHost.writeFile = writeFile;
46754671

4676-
var emitOutput = emitFiles(getDiagnosticsProducingTypeChecker().getEmitResolver(), emitHost, sourceFile);
4672+
var emitOutput = emitFiles(program.getEmitResolver(), emitHost, sourceFile);
46774673

46784674
return {
46794675
outputFiles,

tests/baselines/reference/APISample_compile.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,12 +740,13 @@ declare module "typescript" {
740740
interface Program extends ScriptReferenceHost {
741741
getSourceFiles(): SourceFile[];
742742
getCompilerHost(): CompilerHost;
743+
getEmitResolver(): EmitResolver;
743744
getTypeCheckerDiagnostics(sourceFile?: SourceFile): Diagnostic[];
744745
getTypeCheckerGlobalDiagnostics(): Diagnostic[];
745746
getDiagnostics(sourceFile?: SourceFile): Diagnostic[];
746747
getGlobalDiagnostics(): Diagnostic[];
747748
getDeclarationDiagnostics(sourceFile: SourceFile): Diagnostic[];
748-
getTypeChecker(produceDiagnostics: boolean): TypeChecker;
749+
getTypeChecker(): TypeChecker;
749750
getCommonSourceDirectory(): string;
750751
emitFiles(targetSourceFile?: SourceFile): EmitResult;
751752
isEmitBlocked(sourceFile?: SourceFile): boolean;
@@ -789,7 +790,6 @@ declare module "typescript" {
789790
getSourceFile(fileName: string): SourceFile;
790791
}
791792
interface TypeChecker {
792-
getEmitResolver(): EmitResolver;
793793
getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type;
794794
getDeclaredTypeOfSymbol(symbol: Symbol): Type;
795795
getPropertiesOfType(type: Type): Symbol[];

tests/baselines/reference/APISample_compile.types

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2253,6 +2253,10 @@ declare module "typescript" {
22532253
>getCompilerHost : () => CompilerHost
22542254
>CompilerHost : CompilerHost
22552255

2256+
getEmitResolver(): EmitResolver;
2257+
>getEmitResolver : () => EmitResolver
2258+
>EmitResolver : EmitResolver
2259+
22562260
getTypeCheckerDiagnostics(sourceFile?: SourceFile): Diagnostic[];
22572261
>getTypeCheckerDiagnostics : (sourceFile?: SourceFile) => Diagnostic[]
22582262
>sourceFile : SourceFile
@@ -2279,9 +2283,8 @@ declare module "typescript" {
22792283
>SourceFile : SourceFile
22802284
>Diagnostic : Diagnostic
22812285

2282-
getTypeChecker(produceDiagnostics: boolean): TypeChecker;
2283-
>getTypeChecker : (produceDiagnostics: boolean) => TypeChecker
2284-
>produceDiagnostics : boolean
2286+
getTypeChecker(): TypeChecker;
2287+
>getTypeChecker : () => TypeChecker
22852288
>TypeChecker : TypeChecker
22862289

22872290
getCommonSourceDirectory(): string;
@@ -2409,10 +2412,6 @@ declare module "typescript" {
24092412
interface TypeChecker {
24102413
>TypeChecker : TypeChecker
24112414

2412-
getEmitResolver(): EmitResolver;
2413-
>getEmitResolver : () => EmitResolver
2414-
>EmitResolver : EmitResolver
2415-
24162415
getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type;
24172416
>getTypeOfSymbolAtLocation : (symbol: Symbol, node: Node) => Type
24182417
>symbol : Symbol

0 commit comments

Comments
 (0)