Skip to content

Commit

Permalink
Merge pull request #490 from microsoft/main
Browse files Browse the repository at this point in the history
Create a new pull request by comparing changes across two branches
  • Loading branch information
GulajavaMinistudio authored Oct 10, 2023
2 parents 055d212 + 08d6df0 commit b975330
Show file tree
Hide file tree
Showing 63 changed files with 3,742 additions and 396 deletions.
270 changes: 144 additions & 126 deletions package-lock.json

Large diffs are not rendered by default.

43 changes: 37 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27446,7 +27446,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function getTypeAtSwitchClause(flow: FlowSwitchClause): FlowType {
const expr = flow.switchStatement.expression;
const expr = skipParentheses(flow.switchStatement.expression);
const flowType = getTypeAtFlowNode(flow.antecedent);
let type = getTypeFromFlowType(flowType);
if (isMatchingReference(reference, expr)) {
Expand All @@ -27456,11 +27456,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
type = narrowTypeBySwitchOnTypeOf(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
}
else if (expr.kind === SyntaxKind.TrueKeyword) {
const clause = flow.switchStatement.caseBlock.clauses.find((_, index) => index === flow.clauseStart);
const clauseExpression = clause && clause.kind === SyntaxKind.CaseClause ? clause.expression : undefined;
if (clauseExpression) {
type = narrowType(type, clauseExpression, /*assumeTrue*/ true);
}
type = narrowTypeBySwitchOnTrue(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
}
else {
if (strictNullChecks) {
Expand Down Expand Up @@ -28075,6 +28071,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return getUnionType(map(clauseWitnesses, text => text ? narrowTypeByTypeName(type, text) : neverType));
}

function narrowTypeBySwitchOnTrue(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type {
const defaultIndex = findIndex(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.DefaultClause);
const hasDefaultClause = clauseStart === clauseEnd || (defaultIndex >= clauseStart && defaultIndex < clauseEnd);

// First, narrow away all of the cases that preceded this set of cases.
for (let i = 0; i < clauseStart; i++) {
const clause = switchStatement.caseBlock.clauses[i];
if (clause.kind === SyntaxKind.CaseClause) {
type = narrowType(type, clause.expression, /*assumeTrue*/ false);
}
}

// If our current set has a default, then none the other cases were hit either.
// There's no point in narrowing by the the other cases in the set, since we can
// get here through other paths.
if (hasDefaultClause) {
for (let i = clauseEnd; i < switchStatement.caseBlock.clauses.length; i++) {
const clause = switchStatement.caseBlock.clauses[i];
if (clause.kind === SyntaxKind.CaseClause) {
type = narrowType(type, clause.expression, /*assumeTrue*/ false);
}
}
return type;
}

// Now, narrow based on the cases in this set.
const clauses = switchStatement.caseBlock.clauses.slice(clauseStart, clauseEnd);
return getUnionType(map(clauses, clause => clause.kind === SyntaxKind.CaseClause ? narrowType(type, clause.expression, /*assumeTrue*/ true) : neverType));
}

function isMatchingConstructorReference(expr: Expression) {
return (isPropertyAccessExpression(expr) && idText(expr.name) === "constructor" ||
isElementAccessExpression(expr) && isStringLiteralLike(expr.argumentExpression) && expr.argumentExpression.text === "constructor") &&
Expand Down Expand Up @@ -47904,6 +47930,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled);
},
isImportRequiredByAugmentation,
tryFindAmbientModule: moduleReferenceExpression => {
const node = getParseTreeNode(moduleReferenceExpression);
const moduleSpecifier = node && isStringLiteralLike(node) ? node.text : undefined;
return moduleSpecifier !== undefined ? tryFindAmbientModule(moduleSpecifier, /*withAugmentations*/ true) : undefined;
},
};

function isImportRequiredByAugmentation(node: ImportDeclaration) {
Expand Down
1 change: 1 addition & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,7 @@ export const notImplementedResolver: EmitResolver = {
isBindingCapturedByNode: notImplemented,
getDeclarationStatementsForSourceFile: notImplemented,
isImportRequiredByAugmentation: notImplemented,
tryFindAmbientModule: notImplemented,
};

/**
Expand Down
27 changes: 25 additions & 2 deletions src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ import {
TransformationContext,
transformNodes,
tryCast,
tryGetModuleSpecifierFromDeclaration,
TypeAliasDeclaration,
TypeNode,
TypeParameterDeclaration,
Expand Down Expand Up @@ -345,6 +346,18 @@ export function transformDeclarations(context: TransformationContext) {
refs.set(getOriginalNodeId(container), container);
}

function trackReferencedAmbientModuleFromImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportTypeNode) {
const moduleSpecifier = tryGetModuleSpecifierFromDeclaration(node);
const symbol = moduleSpecifier && resolver.tryFindAmbientModule(moduleSpecifier);
if (symbol?.declarations) {
for (const decl of symbol.declarations) {
if (isAmbientModule(decl) && getSourceFileOfNode(decl) !== currentSourceFile) {
trackReferencedAmbientModule(decl, symbol);
}
}
}
}

function handleSymbolAccessibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) {
if (symbolAccessibilityResult.accessibility === SymbolAccessibility.Accessible) {
// Add aliases back onto the possible imports list if they're not there so we can try them again with updated visibility info
Expand Down Expand Up @@ -1312,6 +1325,7 @@ export function transformDeclarations(context: TransformationContext) {
}
case SyntaxKind.ImportType: {
if (!isLiteralImportTypeNode(input)) return cleanup(input);
trackReferencedAmbientModuleFromImport(input);
return cleanup(factory.updateImportTypeNode(
input,
factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)),
Expand Down Expand Up @@ -1370,6 +1384,7 @@ export function transformDeclarations(context: TransformationContext) {
}
resultHasScopeMarker = true;
// Always visible if the parent node isn't dropped for being not visible
trackReferencedAmbientModuleFromImport(input);
// Rewrite external module names if necessary
return factory.updateExportDeclaration(
input,
Expand Down Expand Up @@ -1456,10 +1471,18 @@ export function transformDeclarations(context: TransformationContext) {
if (shouldStripInternal(input)) return;
switch (input.kind) {
case SyntaxKind.ImportEqualsDeclaration: {
return transformImportEqualsDeclaration(input);
const transformed = transformImportEqualsDeclaration(input);
if (transformed) {
trackReferencedAmbientModuleFromImport(input);
}
return transformed;
}
case SyntaxKind.ImportDeclaration: {
return transformImportDeclaration(input);
const transformed = transformImportDeclaration(input);
if (transformed) {
trackReferencedAmbientModuleFromImport(input);
}
return transformed;
}
}
if (isDeclaration(input) && isDeclarationAndNotVisible(input)) return;
Expand Down
54 changes: 27 additions & 27 deletions src/compiler/tsbuildPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
CompilerHost,
CompilerOptions,
CompilerOptionsValue,
ConfigFileProgramReloadLevel,
convertToRelativePath,
copyProperties,
createCompilerDiagnostic,
Expand Down Expand Up @@ -95,6 +94,7 @@ import {
ProgramBundleEmitBuildInfo,
ProgramHost,
ProgramMultiFileEmitBuildInfo,
ProgramUpdateLevel,
readBuilderProgram,
ReadBuildProgramHost,
resolveConfigFileProjectName,
Expand Down Expand Up @@ -287,7 +287,7 @@ export interface SolutionBuilder<T extends BuilderProgram> {

// Testing only
/** @internal */ getUpToDateStatusOfProject(project: string): UpToDateStatus;
/** @internal */ invalidateProject(configFilePath: ResolvedConfigFilePath, reloadLevel?: ConfigFileProgramReloadLevel): void;
/** @internal */ invalidateProject(configFilePath: ResolvedConfigFilePath, updateLevel?: ProgramUpdateLevel): void;
/** @internal */ close(): void;
}

Expand Down Expand Up @@ -389,7 +389,7 @@ interface SolutionBuilderState<T extends BuilderProgram> extends WatchFactory<Wa

readonly builderPrograms: Map<ResolvedConfigFilePath, T>;
readonly diagnostics: Map<ResolvedConfigFilePath, readonly Diagnostic[]>;
readonly projectPendingBuild: Map<ResolvedConfigFilePath, ConfigFileProgramReloadLevel>;
readonly projectPendingBuild: Map<ResolvedConfigFilePath, ProgramUpdateLevel>;
readonly projectErrorsReported: Map<ResolvedConfigFilePath, true>;

readonly compilerHost: CompilerHost & ReadBuildProgramHost;
Expand Down Expand Up @@ -795,13 +795,13 @@ function clearProjectStatus<T extends BuilderProgram>(state: SolutionBuilderStat
state.diagnostics.delete(resolved);
}

function addProjToQueue<T extends BuilderProgram>({ projectPendingBuild }: SolutionBuilderState<T>, proj: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) {
function addProjToQueue<T extends BuilderProgram>({ projectPendingBuild }: SolutionBuilderState<T>, proj: ResolvedConfigFilePath, updateLevel: ProgramUpdateLevel) {
const value = projectPendingBuild.get(proj);
if (value === undefined) {
projectPendingBuild.set(proj, reloadLevel);
projectPendingBuild.set(proj, updateLevel);
}
else if (value < reloadLevel) {
projectPendingBuild.set(proj, reloadLevel);
else if (value < updateLevel) {
projectPendingBuild.set(proj, updateLevel);
}
}

Expand All @@ -815,7 +815,7 @@ function setupInitialBuild<T extends BuilderProgram>(state: SolutionBuilderState
buildOrder.forEach(configFileName =>
state.projectPendingBuild.set(
toResolvedConfigFilePath(state, configFileName),
ConfigFileProgramReloadLevel.None,
ProgramUpdateLevel.Update,
)
);

Expand Down Expand Up @@ -1402,8 +1402,8 @@ function getNextInvalidatedProjectCreateInfo<T extends BuilderProgram>(
for (let projectIndex = 0; projectIndex < buildOrder.length; projectIndex++) {
const project = buildOrder[projectIndex];
const projectPath = toResolvedConfigFilePath(state, project);
const reloadLevel = state.projectPendingBuild.get(projectPath);
if (reloadLevel === undefined) continue;
const updateLevel = state.projectPendingBuild.get(projectPath);
if (updateLevel === undefined) continue;

if (reportQueue) {
reportQueue = false;
Expand All @@ -1417,14 +1417,14 @@ function getNextInvalidatedProjectCreateInfo<T extends BuilderProgram>(
continue;
}

if (reloadLevel === ConfigFileProgramReloadLevel.Full) {
if (updateLevel === ProgramUpdateLevel.Full) {
watchConfigFile(state, project, projectPath, config);
watchExtendedConfigFiles(state, projectPath, config);
watchWildCardDirectories(state, project, projectPath, config);
watchInputFiles(state, project, projectPath, config);
watchPackageJsonFiles(state, project, projectPath, config);
}
else if (reloadLevel === ConfigFileProgramReloadLevel.Partial) {
else if (updateLevel === ProgramUpdateLevel.RootNamesAndUpdate) {
// Update file names
config.fileNames = getFileNamesFromConfigSpecs(config.options.configFile!.configFileSpecs!, getDirectoryPath(project), config.options, state.parseConfigFileHost);
updateErrorForNoInputFiles(config.fileNames, project, config.options.configFile!.configFileSpecs!, config.errors, canJsonReportNoInputFiles(config.raw));
Expand Down Expand Up @@ -2169,7 +2169,7 @@ function queueReferencingProjects<T extends BuilderProgram>(
break;
}
}
addProjToQueue(state, nextProjectPath, ConfigFileProgramReloadLevel.None);
addProjToQueue(state, nextProjectPath, ProgramUpdateLevel.Update);
break;
}
}
Expand Down Expand Up @@ -2251,7 +2251,7 @@ function cleanWorker<T extends BuilderProgram>(state: SolutionBuilderState<T>, p
}
else {
host.deleteFile(output);
invalidateProject(state, resolvedPath, ConfigFileProgramReloadLevel.None);
invalidateProject(state, resolvedPath, ProgramUpdateLevel.Update);
}
}
}
Expand All @@ -2264,24 +2264,24 @@ function cleanWorker<T extends BuilderProgram>(state: SolutionBuilderState<T>, p
return ExitStatus.Success;
}

function invalidateProject<T extends BuilderProgram>(state: SolutionBuilderState<T>, resolved: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) {
function invalidateProject<T extends BuilderProgram>(state: SolutionBuilderState<T>, resolved: ResolvedConfigFilePath, updateLevel: ProgramUpdateLevel) {
// If host implements getParsedCommandLine, we cant get list of files from parseConfigFileHost
if (state.host.getParsedCommandLine && reloadLevel === ConfigFileProgramReloadLevel.Partial) {
reloadLevel = ConfigFileProgramReloadLevel.Full;
if (state.host.getParsedCommandLine && updateLevel === ProgramUpdateLevel.RootNamesAndUpdate) {
updateLevel = ProgramUpdateLevel.Full;
}
if (reloadLevel === ConfigFileProgramReloadLevel.Full) {
if (updateLevel === ProgramUpdateLevel.Full) {
state.configFileCache.delete(resolved);
state.buildOrder = undefined;
}
state.needsSummary = true;
clearProjectStatus(state, resolved);
addProjToQueue(state, resolved, reloadLevel);
addProjToQueue(state, resolved, updateLevel);
enableCache(state);
}

function invalidateProjectAndScheduleBuilds<T extends BuilderProgram>(state: SolutionBuilderState<T>, resolvedPath: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) {
function invalidateProjectAndScheduleBuilds<T extends BuilderProgram>(state: SolutionBuilderState<T>, resolvedPath: ResolvedConfigFilePath, updateLevel: ProgramUpdateLevel) {
state.reportFileChangeDetected = true;
invalidateProject(state, resolvedPath, reloadLevel);
invalidateProject(state, resolvedPath, updateLevel);
scheduleBuildInvalidatedProject(state, 250, /*changeDetected*/ true);
}

Expand Down Expand Up @@ -2344,7 +2344,7 @@ function watchConfigFile<T extends BuilderProgram>(state: SolutionBuilderState<T
watchFile(
state,
resolved,
() => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Full),
() => invalidateProjectAndScheduleBuilds(state, resolvedPath, ProgramUpdateLevel.Full),
PollingInterval.High,
parsed?.watchOptions,
WatchType.ConfigFile,
Expand All @@ -2362,7 +2362,7 @@ function watchExtendedConfigFiles<T extends BuilderProgram>(state: SolutionBuild
watchFile(
state,
extendedConfigFileName,
() => state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach(projectConfigFilePath => invalidateProjectAndScheduleBuilds(state, projectConfigFilePath, ConfigFileProgramReloadLevel.Full)),
() => state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach(projectConfigFilePath => invalidateProjectAndScheduleBuilds(state, projectConfigFilePath, ProgramUpdateLevel.Full)),
PollingInterval.High,
parsed?.watchOptions,
WatchType.ExtendedConfigFile,
Expand Down Expand Up @@ -2395,7 +2395,7 @@ function watchWildCardDirectories<T extends BuilderProgram>(state: SolutionBuild
})
) return;

invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Partial);
invalidateProjectAndScheduleBuilds(state, resolvedPath, ProgramUpdateLevel.RootNamesAndUpdate);
},
flags,
parsed?.watchOptions,
Expand All @@ -2415,7 +2415,7 @@ function watchInputFiles<T extends BuilderProgram>(state: SolutionBuilderState<T
watchFile(
state,
input,
() => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None),
() => invalidateProjectAndScheduleBuilds(state, resolvedPath, ProgramUpdateLevel.Update),
PollingInterval.Low,
parsed?.watchOptions,
WatchType.SourceFile,
Expand All @@ -2436,7 +2436,7 @@ function watchPackageJsonFiles<T extends BuilderProgram>(state: SolutionBuilderS
watchFile(
state,
path,
() => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None),
() => invalidateProjectAndScheduleBuilds(state, resolvedPath, ProgramUpdateLevel.Update),
PollingInterval.High,
parsed?.watchOptions,
WatchType.PackageJson,
Expand Down Expand Up @@ -2503,7 +2503,7 @@ function createSolutionBuilderWorker<T extends BuilderProgram>(watch: boolean, h
const configFilePath = toResolvedConfigFilePath(state, configFileName);
return getUpToDateStatus(state, parseConfigFile(state, configFileName, configFilePath), configFilePath);
},
invalidateProject: (configFilePath, reloadLevel) => invalidateProject(state, configFilePath, reloadLevel || ConfigFileProgramReloadLevel.None),
invalidateProject: (configFilePath, updateLevel) => invalidateProject(state, configFilePath, updateLevel || ProgramUpdateLevel.Update),
close: () => stopWatching(state),
};
}
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5675,6 +5675,7 @@ export interface EmitResolver {
isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean;
getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker, bundled?: boolean): Statement[] | undefined;
isImportRequiredByAugmentation(decl: ImportDeclaration): boolean;
tryFindAmbientModule(moduleReferenceExpression: Expression): Symbol | undefined;
}

// dprint-ignore
Expand Down
Loading

0 comments on commit b975330

Please sign in to comment.