fix(ivy): always re-analyze the program during incremental rebuilds (#33862)
Previously, the ngtsc compiler attempted to reuse analysis work from the previous program during an incremental build. To do this, it had to prove that the work was safe to reuse - that no changes made to the new program would invalidate the previous analysis. The implementation of this had a significant design flaw: if the previous program had errors, the previous analysis would be missing significant information, and the dependency graph extracted from it would not be sufficient to determine which files should be re-analyzed to fill in the gaps. This often meant that the build output after an error was resolved would be wholly incorrect. This commit switches ngtsc to take a simpler approach to incremental rebuilds. Instead of attempting to reuse prior analysis work, the entire program is re-analyzed with each compilation. This is actually not as expensive as one might imagine - analysis is a fairly small part of overall compilation time. Based on the dependency graph extracted during this analysis, the compiler then can make accurate decisions on whether to emit specific files. A new suite of tests is added to validate behavior in the presence of source code level errors. This new approach is dramatically simpler than the previous algorithm, and should always produce correct results for a semantically correct program.s Fixes #32388 Fixes #32214 PR Close #33862
This commit is contained in:
@ -7,6 +7,6 @@
|
||||
*/
|
||||
|
||||
export {ExportScope, ScopeData} from './src/api';
|
||||
export {ComponentScopeReader, ComponentScopeRegistry, CompoundComponentScopeReader} from './src/component_scope';
|
||||
export {ComponentScopeReader, CompoundComponentScopeReader} from './src/component_scope';
|
||||
export {DtsModuleScopeResolver, MetadataDtsModuleScopeResolver} from './src/dependency';
|
||||
export {LocalModuleScope, LocalModuleScopeRegistry, LocalNgModuleData} from './src/local';
|
||||
|
@ -8,14 +8,6 @@
|
||||
import {ClassDeclaration} from '../../reflection';
|
||||
import {LocalModuleScope} from './local';
|
||||
|
||||
/**
|
||||
* Register information about the compilation scope of components.
|
||||
*/
|
||||
export interface ComponentScopeRegistry {
|
||||
registerComponentScope(clazz: ClassDeclaration, scope: LocalModuleScope): void;
|
||||
setComponentAsRequiringRemoteScoping(clazz: ClassDeclaration): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read information about the compilation scope of components.
|
||||
*/
|
||||
@ -24,17 +16,6 @@ export interface ComponentScopeReader {
|
||||
getRequiresRemoteScope(clazz: ClassDeclaration): boolean|null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A noop registry that doesn't do anything.
|
||||
*
|
||||
* This can be used in tests and cases where we don't care about the compilation scopes
|
||||
* being registered.
|
||||
*/
|
||||
export class NoopComponentScopeRegistry implements ComponentScopeRegistry {
|
||||
registerComponentScope(clazz: ClassDeclaration, scope: LocalModuleScope): void {}
|
||||
setComponentAsRequiringRemoteScoping(clazz: ClassDeclaration): void {}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `ComponentScopeReader` that reads from an ordered set of child readers until it obtains the
|
||||
* requested scope.
|
||||
|
@ -16,7 +16,7 @@ import {ClassDeclaration} from '../../reflection';
|
||||
import {identifierOfNode, nodeNameForError} from '../../util/src/typescript';
|
||||
|
||||
import {ExportScope, ScopeData} from './api';
|
||||
import {ComponentScopeReader, ComponentScopeRegistry, NoopComponentScopeRegistry} from './component_scope';
|
||||
import {ComponentScopeReader} from './component_scope';
|
||||
import {DtsModuleScopeResolver} from './dependency';
|
||||
|
||||
export interface LocalNgModuleData {
|
||||
@ -104,8 +104,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop
|
||||
|
||||
constructor(
|
||||
private localReader: MetadataReader, private dependencyScopeReader: DtsModuleScopeResolver,
|
||||
private refEmitter: ReferenceEmitter, private aliasingHost: AliasingHost|null,
|
||||
private componentScopeRegistry: ComponentScopeRegistry = new NoopComponentScopeRegistry()) {}
|
||||
private refEmitter: ReferenceEmitter, private aliasingHost: AliasingHost|null) {}
|
||||
|
||||
/**
|
||||
* Add an NgModule's data to the registry.
|
||||
@ -126,9 +125,6 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop
|
||||
const scope = !this.declarationToModule.has(clazz) ?
|
||||
null :
|
||||
this.getScopeOfModule(this.declarationToModule.get(clazz) !);
|
||||
if (scope !== null) {
|
||||
this.componentScopeRegistry.registerComponentScope(clazz, scope);
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
@ -357,7 +353,6 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop
|
||||
*/
|
||||
setComponentAsRequiringRemoteScoping(node: ClassDeclaration): void {
|
||||
this.remoteScoping.add(node);
|
||||
this.componentScopeRegistry.setComponentAsRequiringRemoteScoping(node);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user