mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 20:25:23 -06:00
Remove the dependency that TypeChecker and Emitter have on Program.
Instead, these layers explicitly specify the functionality they need, and don't take in anything extra.
This commit is contained in:
parent
b665323d45
commit
f5ad79fe7a
@ -9,7 +9,7 @@ module ts {
|
||||
/// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors
|
||||
/// If fullTypeCheck === false, the typechecker can take shortcuts and skip checks that only produce errors.
|
||||
/// NOTE: checks that somehow affect decisions being made during typechecking should be executed in both cases.
|
||||
export function createTypeChecker(program: Program, produceDiagnostics: boolean): TypeChecker {
|
||||
export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
|
||||
var Symbol = objectAllocator.getSymbolConstructor();
|
||||
var Type = objectAllocator.getTypeConstructor();
|
||||
var Signature = objectAllocator.getSignatureConstructor();
|
||||
@ -19,13 +19,13 @@ module ts {
|
||||
var emptyArray: any[] = [];
|
||||
var emptySymbols: SymbolTable = {};
|
||||
|
||||
var compilerOptions = program.getCompilerOptions();
|
||||
var compilerOptions = host.getCompilerOptions();
|
||||
var emitResolver = createResolver();
|
||||
|
||||
var checker: TypeChecker = {
|
||||
getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"),
|
||||
getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"),
|
||||
getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"),
|
||||
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
|
||||
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
|
||||
getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount"),
|
||||
getTypeCount: () => typeCount,
|
||||
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
|
||||
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
|
||||
@ -55,8 +55,6 @@ module ts {
|
||||
getSignatureFromDeclaration,
|
||||
isImplementationOfOverload,
|
||||
getAliasedSymbol: resolveImport,
|
||||
hasEarlyErrors,
|
||||
isEmitBlocked,
|
||||
getEmitResolver: () => emitResolver,
|
||||
};
|
||||
|
||||
@ -277,7 +275,7 @@ module ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
var sourceFiles = program.getSourceFiles();
|
||||
var sourceFiles = host.getSourceFiles();
|
||||
return sourceFiles.indexOf(file1) <= sourceFiles.indexOf(file2);
|
||||
}
|
||||
|
||||
@ -517,7 +515,7 @@ module ts {
|
||||
}
|
||||
while (true) {
|
||||
var filename = normalizePath(combinePaths(searchPath, moduleName));
|
||||
var sourceFile = program.getSourceFile(filename + ".ts") || program.getSourceFile(filename + ".d.ts");
|
||||
var sourceFile = host.getSourceFile(filename + ".ts") || host.getSourceFile(filename + ".d.ts");
|
||||
if (sourceFile || isRelative) break;
|
||||
var parentPath = getDirectoryPath(searchPath);
|
||||
if (parentPath === searchPath) break;
|
||||
@ -3394,7 +3392,7 @@ module ts {
|
||||
if (containingMessageChain) {
|
||||
errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo);
|
||||
}
|
||||
addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, program.getCompilerHost().getNewLine()));
|
||||
addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, host.getCompilerHost().getNewLine()));
|
||||
}
|
||||
return result !== Ternary.False;
|
||||
|
||||
@ -8323,7 +8321,7 @@ module ts {
|
||||
|
||||
var errorInfo = chainDiagnosticMessages(undefined, Diagnostics.Named_properties_0_of_types_1_and_2_are_not_identical, prop.name, typeName1, typeName2);
|
||||
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2);
|
||||
addDiagnostic(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo, program.getCompilerHost().getNewLine()));
|
||||
addDiagnostic(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo, host.getCompilerHost().getNewLine()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8934,7 +8932,7 @@ module ts {
|
||||
checkSourceFile(sourceFile);
|
||||
return filter(getSortedDiagnostics(), d => d.file === sourceFile);
|
||||
}
|
||||
forEach(program.getSourceFiles(), checkSourceFile);
|
||||
forEach(host.getSourceFiles(), checkSourceFile);
|
||||
return getSortedDiagnostics();
|
||||
}
|
||||
|
||||
@ -9451,16 +9449,6 @@ module ts {
|
||||
return getDiagnostics(sourceFile).length > 0 || getGlobalDiagnostics().length > 0;
|
||||
}
|
||||
|
||||
function isEmitBlocked(sourceFile?: SourceFile): boolean {
|
||||
return program.getDiagnostics(sourceFile).length !== 0 ||
|
||||
hasEarlyErrors(sourceFile) ||
|
||||
(compilerOptions.noEmitOnError && getDiagnostics(sourceFile).length !== 0);
|
||||
}
|
||||
|
||||
function hasEarlyErrors(sourceFile?: SourceFile): boolean {
|
||||
return forEach(getDiagnostics(sourceFile), d => d.isEarly);
|
||||
}
|
||||
|
||||
function isImportResolvedToValue(symbol: Symbol): boolean {
|
||||
var target = resolveImport(symbol);
|
||||
// const enums and modules that contain only const enums are not considered values from the emit perespective
|
||||
@ -9556,7 +9544,6 @@ module ts {
|
||||
getEnumMemberValue,
|
||||
isTopLevelValueImportWithEntityName,
|
||||
hasSemanticErrors,
|
||||
isEmitBlocked,
|
||||
isDeclarationVisible,
|
||||
isImplementationOfOverload,
|
||||
writeTypeOfDeclaration,
|
||||
@ -9570,12 +9557,12 @@ module ts {
|
||||
|
||||
function initializeTypeChecker() {
|
||||
// Bind all source files and propagate errors
|
||||
forEach(program.getSourceFiles(), file => {
|
||||
forEach(host.getSourceFiles(), file => {
|
||||
bindSourceFile(file);
|
||||
forEach(file.semanticDiagnostics, addDiagnostic);
|
||||
});
|
||||
// Initialize global symbol table
|
||||
forEach(program.getSourceFiles(), file => {
|
||||
forEach(host.getSourceFiles(), file => {
|
||||
if (!isExternalModule(file)) {
|
||||
extendSymbolTable(globals, file.locals);
|
||||
}
|
||||
|
||||
@ -4138,7 +4138,7 @@ module ts {
|
||||
if (targetSourceFile === undefined) {
|
||||
// No targetSourceFile is specified (e.g. calling emitter from batch compiler)
|
||||
hasSemanticErrors = resolver.hasSemanticErrors();
|
||||
isEmitBlocked = resolver.isEmitBlocked();
|
||||
isEmitBlocked = host.isEmitBlocked();
|
||||
|
||||
forEach(host.getSourceFiles(), sourceFile => {
|
||||
if (shouldEmitToOwnFile(sourceFile, compilerOptions)) {
|
||||
@ -4156,7 +4156,7 @@ module ts {
|
||||
if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) {
|
||||
// If shouldEmitToOwnFile returns true or targetSourceFile is an external module file, then emit targetSourceFile in its own output file
|
||||
hasSemanticErrors = resolver.hasSemanticErrors(targetSourceFile);
|
||||
isEmitBlocked = resolver.isEmitBlocked(targetSourceFile);
|
||||
isEmitBlocked = host.isEmitBlocked(targetSourceFile);
|
||||
|
||||
var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js");
|
||||
emitFile(jsFilePath, targetSourceFile);
|
||||
@ -4167,7 +4167,7 @@ module ts {
|
||||
forEach(host.getSourceFiles(), sourceFile => {
|
||||
if (!shouldEmitToOwnFile(sourceFile, compilerOptions)) {
|
||||
hasSemanticErrors = hasSemanticErrors || resolver.hasSemanticErrors(sourceFile);
|
||||
isEmitBlocked = isEmitBlocked || resolver.isEmitBlocked(sourceFile);
|
||||
isEmitBlocked = isEmitBlocked || host.isEmitBlocked(sourceFile);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -102,13 +102,28 @@ module ts {
|
||||
getDeclarationDiagnostics: getDeclarationDiagnostics,
|
||||
getTypeChecker,
|
||||
getCommonSourceDirectory: () => commonSourceDirectory,
|
||||
emitFiles: invokeEmitter
|
||||
emitFiles: invokeEmitter,
|
||||
isEmitBlocked,
|
||||
};
|
||||
return program;
|
||||
|
||||
function hasEarlyErrors(sourceFile?: SourceFile): boolean {
|
||||
return forEach(getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile), d => d.isEarly);
|
||||
}
|
||||
|
||||
function isEmitBlocked(sourceFile?: SourceFile): boolean {
|
||||
return getDiagnostics(sourceFile).length !== 0 ||
|
||||
hasEarlyErrors(sourceFile) ||
|
||||
(options.noEmitOnError && getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile).length !== 0);
|
||||
}
|
||||
|
||||
function getDiagnosticsProducingTypeChecker() {
|
||||
return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ true));
|
||||
}
|
||||
|
||||
function getTypeChecker(produceDiagnostics: boolean) {
|
||||
if (produceDiagnostics) {
|
||||
return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, produceDiagnostics));
|
||||
return getDiagnosticsProducingTypeChecker();
|
||||
}
|
||||
else {
|
||||
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, produceDiagnostics));
|
||||
@ -116,14 +131,14 @@ module ts {
|
||||
}
|
||||
|
||||
function getDeclarationDiagnostics(targetSourceFile: SourceFile): Diagnostic[]{
|
||||
var fullTypeChecker = getTypeChecker(/*produceDiagnostics:*/true);
|
||||
fullTypeChecker.getDiagnostics(targetSourceFile);
|
||||
var resolver = fullTypeChecker.getEmitResolver();
|
||||
var typeChecker = getDiagnosticsProducingTypeChecker();
|
||||
typeChecker.getDiagnostics(targetSourceFile);
|
||||
var resolver = typeChecker.getEmitResolver();
|
||||
return ts.getDeclarationDiagnostics(program, resolver, targetSourceFile);
|
||||
}
|
||||
|
||||
function invokeEmitter(targetSourceFile?: SourceFile) {
|
||||
var resolver = getTypeChecker(/*produceDiagnostics:*/true).getEmitResolver();
|
||||
var resolver = getDiagnosticsProducingTypeChecker().getEmitResolver();
|
||||
return emitFiles(resolver, program, targetSourceFile);
|
||||
}
|
||||
|
||||
|
||||
@ -286,7 +286,7 @@ module ts {
|
||||
var checker = program.getTypeChecker(/*fullTypeCheckMode*/ true);
|
||||
var checkStart = new Date().getTime();
|
||||
errors = checker.getDiagnostics();
|
||||
if (checker.isEmitBlocked()) {
|
||||
if (program.isEmitBlocked()) {
|
||||
exitStatus = EmitReturnStatus.AllOutputGenerationSkipped;
|
||||
}
|
||||
else {
|
||||
|
||||
@ -926,7 +926,9 @@ module ts {
|
||||
// will throw an invalid operation exception.
|
||||
getTypeChecker(produceDiagnostics: boolean): TypeChecker;
|
||||
getCommonSourceDirectory(): string;
|
||||
|
||||
emitFiles(targetSourceFile?: SourceFile): EmitResult;
|
||||
isEmitBlocked(sourceFile?: SourceFile): boolean;
|
||||
}
|
||||
|
||||
export interface SourceMapSpan {
|
||||
@ -966,6 +968,32 @@ module ts {
|
||||
sourceMaps: SourceMapData[]; // Array of sourceMapData if compiler emitted sourcemaps
|
||||
}
|
||||
|
||||
export interface TypeCheckerHost {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getCompilerHost(): CompilerHost;
|
||||
|
||||
getSourceFiles(): SourceFile[];
|
||||
getSourceFile(filename: string): SourceFile;
|
||||
//getSourceFiles(): SourceFile[];
|
||||
//getCompilerOptions(): CompilerOptions;
|
||||
|
||||
//getDiagnostics(sourceFile?: SourceFile): Diagnostic[];
|
||||
//getGlobalDiagnostics(): Diagnostic[];
|
||||
//getDeclarationDiagnostics(sourceFile: SourceFile): Diagnostic[];
|
||||
|
||||
//// Gets a type checker that can be used to semantically analyze source fils in the program.
|
||||
//// The 'produceDiagnostics' flag determines if the checker will produce diagnostics while
|
||||
//// analyzing the code. It can be set to 'false' to make many type checking operaitons
|
||||
//// faster. With this flag set, the checker can avoid codepaths only necessary to produce
|
||||
//// diagnostics, but not necessary to answer semantic questions about the code.
|
||||
////
|
||||
//// If 'produceDiagnostics' is false, then any calls to get diagnostics from the TypeChecker
|
||||
//// will throw an invalid operation exception.
|
||||
//getTypeChecker(produceDiagnostics: boolean): TypeChecker;
|
||||
//getCommonSourceDirectory(): string;
|
||||
//emitFiles(targetSourceFile?: SourceFile): EmitResult;
|
||||
}
|
||||
|
||||
export interface TypeChecker {
|
||||
getEmitResolver(): EmitResolver;
|
||||
getDiagnostics(sourceFile?: SourceFile): Diagnostic[];
|
||||
@ -997,7 +1025,7 @@ module ts {
|
||||
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
|
||||
isUndefinedSymbol(symbol: Symbol): boolean;
|
||||
isArgumentsSymbol(symbol: Symbol): boolean;
|
||||
isEmitBlocked(sourceFile?: SourceFile): boolean;
|
||||
|
||||
// Returns the constant value of this enum member, or 'undefined' if the enum member has a computed value.
|
||||
getEnumMemberValue(node: EnumMember): number;
|
||||
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
|
||||
@ -1080,6 +1108,7 @@ module ts {
|
||||
getCompilerHost(): CompilerHost;
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getCommonSourceDirectory(): string;
|
||||
isEmitBlocked(sourceFile?: SourceFile): boolean;
|
||||
}
|
||||
|
||||
export interface EmitResolver {
|
||||
@ -1099,7 +1128,6 @@ module ts {
|
||||
isEntityNameVisible(entityName: EntityName, enclosingDeclaration: Node): SymbolVisibilityResult;
|
||||
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
|
||||
getConstantValue(node: PropertyAccessExpression | ElementAccessExpression): number;
|
||||
isEmitBlocked(sourceFile?: SourceFile): boolean;
|
||||
isUnknownIdentifier(location: Node, name: string): boolean;
|
||||
}
|
||||
|
||||
|
||||
@ -1046,7 +1046,7 @@ module Harness {
|
||||
|
||||
var checker = program.getTypeChecker(/*produceDiagnostics*/ true);
|
||||
|
||||
var isEmitBlocked = checker.isEmitBlocked();
|
||||
var isEmitBlocked = program.isEmitBlocked();
|
||||
|
||||
// only emit if there weren't parse errors
|
||||
var emitResult: ts.EmitResult;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user