Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix-ups for "significant proof checking refactoring" #48

Merged
merged 21 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f70deac
Refactor `SessionState` & highlight vulnerabilities
GlebSolovev Nov 15, 2024
5b5abb1
Restructure theorem rankers, add comments
GlebSolovev Nov 15, 2024
e64f491
Remove redundant null-checks for theorem proof
GlebSolovev Nov 15, 2024
1d158bc
Make code style of `parsedTypes.ts` consistent
GlebSolovev Nov 15, 2024
66d0d43
Format code
GlebSolovev Nov 15, 2024
16831af
Use `ProofGoal` instead of `Goal<PpString>`
GlebSolovev Nov 15, 2024
ca16531
Implement `getFirstGoalOrThrow` wrapper properly
GlebSolovev Nov 15, 2024
34d48f3
Improve code style of coq-lsp tests
GlebSolovev Nov 15, 2024
8b3a621
Introduce `withTextDocument` wrapper
GlebSolovev Nov 15, 2024
8abe2eb
Fix `imm` submodule commit
GlebSolovev Nov 15, 2024
ea7805b
Introduce with-coq-lsp wrappers, dispose client correctly
GlebSolovev Nov 15, 2024
b0c20a4
Fix `SessionState` bugs, improve its code style
GlebSolovev Nov 16, 2024
da02a28
Fix coq-lsp usage in legacy benchmarks, refactor args
GlebSolovev Nov 16, 2024
1cc6ffd
Prevent legacy benchmarks from creating empty report on start
GlebSolovev Nov 16, 2024
649402d
Fix coq-lsp usage at parsing stage of benchmarks
GlebSolovev Nov 16, 2024
729153b
Document `CoqLspClient` invariants
GlebSolovev Nov 16, 2024
09f914a
Improve `CoqProofChecker` code style
GlebSolovev Nov 16, 2024
a129ca9
Fix bugs in internal signatures of benchmarks
GlebSolovev Nov 16, 2024
78dd974
Move abort utils into `core`
GlebSolovev Nov 16, 2024
7c3d5d6
Structure `extension` directory
GlebSolovev Nov 16, 2024
3a8ffc2
Support abort signal set-up in coq-lsp client wrappers
GlebSolovev Nov 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ export async function benchmarkSingleCompletionGeneration<
generationArgs.completionContext,
generationArgs.sourceFileEnvironment,
generationArgs.workspaceRoot,
logger
logger,
abortSignal
);
} catch (error) {
if (error instanceof ProofsCheckFailedError) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export abstract class AbstractProofsChecker {
completionContext: CompletionContext,
sourceFileEnvironment: SourceFileEnvironment,
workspaceRoot: WorkspaceRoot,
logger: BenchmarkingLogger
logger: BenchmarkingLogger,
abortSignal?: AbortSignal
): Promise<ProofsCheckResult>;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createTestCoqLspClient } from "../../../../../../coqLsp/coqLspBuilders";
import { withDocumentOpenedByTestCoqLsp } from "../../../../../../coqLsp/coqLspBuilders";
import { CoqLspTimeoutError } from "../../../../../../coqLsp/coqLspTypes";

import {
Expand All @@ -7,8 +7,8 @@ import {
} from "../../../../../../core/coqProofChecker";

import { stringifyAnyValue } from "../../../../../../utils/printers";
import { Uri } from "../../../../../../utils/uri";
import { BenchmarkingLogger } from "../../../../logging/benchmarkingLogger";
import { deserializeUri } from "../../../../structures/common/serializedUri";
import { LogsIPCSender } from "../../../../utils/subprocessUtils/ipc/onParentProcessCallExecutor/logsIpcSender";
import { TimeMark } from "../../measureUtils";

Expand All @@ -28,31 +28,29 @@ export namespace CheckProofsImpl {

export async function checkProofsMeasured(
args: Signature.Args,
providedLogger: ProvidedLogger
providedLogger: ProvidedLogger,
abortSignal?: AbortSignal
): Promise<Signature.Result> {
const coqLspClient = await createTestCoqLspClient(
args.workspaceRootPath
);
const coqProofChecker = new CoqProofChecker(coqLspClient);
// TODO: each coq proof checker should use its own prefix to work good in parallel (many checkers for the same theorem in the same file)
const fileUri = deserializeUri(args.serializedFileUri);
const timeMark = new TimeMark();

try {
const timeMark = new TimeMark();
const fileUri = Uri.fromPath(args.fileUri);

// TODO: [@Gleb Solovev] Pay Atteniton that it was previously done by the CoqProofChecker
await coqLspClient.openTextDocument(fileUri);

const proofCheckResults = await coqProofChecker.checkProofs(
fileUri,
args.documentVersion,
args.checkAtPosition,
args.preparedProofs
const proofCheckResults = await withDocumentOpenedByTestCoqLsp(
{ uri: fileUri, version: args.documentVersion },
{
workspaceRootPath: args.workspaceRootPath,
abortSignal: abortSignal,
},
(coqLspClient) =>
new CoqProofChecker(coqLspClient).checkProofs(
fileUri,
args.documentVersion,
args.positionToCheckAt,
args.preparedProofs
)
);

await coqLspClient.closeTextDocument(fileUri);

const proofsValidationMillis = timeMark.measureElapsedMillis();

return buildSuccessResult(
proofCheckResults,
proofsValidationMillis,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { JSONSchemaType } from "ajv";

import { ProofCheckResult } from "../../../../../../core/coqProofChecker";

import { SerializedUri } from "../../../../structures/common/serializedUri";

export namespace CheckProofsInternalSignature {
export const subprocessName = "Check generated proofs";

export interface Args {
workspaceRootPath: string | undefined;
fileUri: string;
serializedFileUri: SerializedUri;
documentVersion: number;
checkAtPosition: Position;

positionToCheckAt: Position;
preparedProofs: string[];
}

Expand Down Expand Up @@ -80,21 +81,26 @@ export namespace CheckProofsInternalSignature {
type: "string",
nullable: true,
},
fileUri: {
serializedFileUri: {
type: "string",
},
documentVersion: {
type: "number",
},
checkAtPosition: positionSchema,
positionToCheckAt: positionSchema,
preparedProofs: {
type: "array",
items: {
type: "string",
},
},
},
required: ["fileUri", "documentVersion", "preparedProofs"],
required: [
"serializedFileUri",
"documentVersion",
"positionToCheckAt",
"preparedProofs",
],
additionalProperties: false,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
SourceFileEnvironment,
} from "../../../../../../core/completionGenerationContext";

import { serializeUri } from "../../../../structures/common/serializedUri";
import {
WorkspaceRoot,
isStandaloneFilesRoot,
Expand All @@ -27,9 +28,9 @@ export namespace ProofsCheckerUtils {
workspaceRootPath: isStandaloneFilesRoot(workspaceRoot)
? undefined
: workspaceRoot.directoryPath,
fileUri: sourceFileEnvironment.fileUri.toString(),
serializedFileUri: serializeUri(sourceFileEnvironment.fileUri),
documentVersion: sourceFileEnvironment.documentVersion,
checkAtPosition: completionContext.admitRange.start,
positionToCheckAt: completionContext.admitRange.start,
preparedProofs: preparedProofs,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export class LocalProofsChecker extends AbstractProofsChecker {
completionContext: CompletionContext,
sourceFileEnvironment: SourceFileEnvironment,
workspaceRoot: WorkspaceRoot,
logger: BenchmarkingLogger
logger: BenchmarkingLogger,
abortSignal: AbortSignal
): Promise<ProofsCheckResult> {
const args = ProofsCheckerUtils.buildArgs(
preparedProofs,
Expand All @@ -36,7 +37,8 @@ export class LocalProofsChecker extends AbstractProofsChecker {
{
logger: logger,
logSuccess: false,
}
},
abortSignal
);
return ProofsCheckerUtils.unpackSuccessResultOrThrow(proofsCheckResult);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ namespace UpdateCacheHolders {

if (cachedFile.getDocumentVersion() !== parsedFile.documentVersion) {
cacheUpdaterLogger.debug(
`* file version update: ${cachedFile.getDocumentVersion()} -> ${parsedFile.documentVersion}`
`* document version update: ${cachedFile.getDocumentVersion()} -> ${parsedFile.documentVersion}`
);
}
cachedFile.updateDocumentVersion(parsedFile.documentVersion);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { createTestCoqLspClient } from "../../../../../coqLsp/coqLspBuilders";
import { withTestCoqLspClient } from "../../../../../coqLsp/coqLspBuilders";
import { CoqLspClient } from "../../../../../coqLsp/coqLspClient";
import { CoqLspError } from "../../../../../coqLsp/coqLspTypes";

import { createSourceFileEnvironment } from "../../../../../core/inspectSourceFile";

import { asErrorOrRethrow } from "../../../../../utils/errorsUtils";
import { Uri } from "../../../../../utils/uri";
import { BenchmarkingLogger } from "../../../logging/benchmarkingLogger";
import { TargetType } from "../../../structures/benchmarkingCore/completionGenerationTask";
Expand Down Expand Up @@ -40,49 +42,70 @@ export namespace ParseCoqProjectImpl {
args: Signature.ArgsModels.Args,
logger: Logger
): Promise<Signature.ResultModels.Result> {
const coqLspClient = await createTestCoqLspClient(
args.workspaceRootPath
);
const parsedWorkspace: Signature.ResultModels.Result = {};
for (const filePath in args.workspaceTargets) {
const fileTargets = args.workspaceTargets[filePath];
const serializedParsedFile = await openAndParseSourceFile(
filePath,
coqLspClient,
logger
);
const parsedFileResults: Signature.ResultModels.ParsedFileResults =
{
serializedParsedFile: serializedParsedFile,
parsedFileTargets: await extractFileTargetsFromFile(
fileTargets,
serializedParsedFile,
coqLspClient,
logger
),
};
parsedWorkspace[filePath] = parsedFileResults;
}

// Note: specific abort controller is not passed here, since
// the abort behaviour is not supported (and not needed) at the parsing stage.
await withTestCoqLspClient(
{ workspaceRootPath: args.workspaceRootPath },
async (coqLspClient) => {
for (const filePath in args.workspaceTargets) {
parsedWorkspace[filePath] =
await coqLspClient.withTextDocument(
{ uri: Uri.fromPath(filePath) },
() =>
parseFileTargets(
args.workspaceTargets[filePath],
filePath,
coqLspClient,
logger
)
);
}
}
);

logger.debug(
`Successfully parsed Coq project: analyzed ${Object.keys(parsedWorkspace).length} files`
);
return parsedWorkspace;
}

async function openAndParseSourceFile(
async function parseFileTargets(
fileTargets: Signature.ArgsModels.FileTarget[],
filePath: string,
coqLspClient: CoqLspClient,
logger: Logger
): Promise<Signature.ResultModels.ParsedFileResults> {
const serializedParsedFile = await parseSourceFile(
filePath,
coqLspClient,
logger
);
return {
serializedParsedFile: serializedParsedFile,
parsedFileTargets: await extractFileTargetsFromFile(
fileTargets,
serializedParsedFile,
coqLspClient,
logger
),
};
}

async function parseSourceFile(
filePath: string,
coqLspClient: CoqLspClient,
logger: Logger
): Promise<SerializedParsedCoqFile> {
const mockDocumentVersion = 1;
const sourceFileUri = Uri.fromPath(filePath);
await coqLspClient.openTextDocument(sourceFileUri);
// TODO: [@Gleb Solovev] Do not create this Abort Controller but pass
// the one created at the top
// TODO + check coq-lsp creation in benchmarks
const abortController = new AbortController();
const sourceFileEnvironment = await createSourceFileEnvironment(
mockDocumentVersion,
sourceFileUri,
Uri.fromPath(filePath),
coqLspClient,
abortController.signal
);
Expand Down Expand Up @@ -163,20 +186,25 @@ export namespace ParseCoqProjectImpl {
proofStep: SerializedProofStep,
targetType: TargetType,
knownGoal: SerializedGoal | undefined
) => Promise<Signature.ResultModels.ParsedFileTarget> = (
) => Promise<Signature.ResultModels.ParsedFileTarget> = async (
proofStep,
targetType,
knownGoal
) =>
buildParsedFileTarget(
proofStep,
targetType,
theorem.name,
knownGoal,
serializedParsedFile,
coqLspClient,
logger
);
) => {
return {
theoremName: theorem.name,
targetType: targetType,
goalToProve:
knownGoal ??
(await parseGoal(
proofStep,
serializedParsedFile,
coqLspClient,
logger
)),
positionRange: proofStep.range,
};
};
switch (requestType) {
case TargetRequestType.THEOREM_PROOF:
// THEOREM_PROOF goals are already parsed within the theorems,
Expand All @@ -197,46 +225,33 @@ export namespace ParseCoqProjectImpl {
}
}

async function buildParsedFileTarget(
async function parseGoal(
proofStep: SerializedProofStep,
targetType: TargetType,
theoremName: string,
knownGoal: SerializedGoal | undefined,
serializedParsedFile: SerializedParsedCoqFile,
coqLspClient: CoqLspClient,
logger: Logger
): Promise<Signature.ResultModels.ParsedFileTarget> {
let serializedGoal = knownGoal;
if (serializedGoal === undefined) {
const goals = await coqLspClient.getGoalsAtPoint(
): Promise<SerializedGoal> {
const startPosition = deserializeCodeElementPosition(
proofStep.range.start
);
try {
const goal = await coqLspClient.getFirstGoalAtPointOrThrow(
proofStep.range.start,
Uri.fromPath(serializedParsedFile.filePath),
serializedParsedFile.documentVersion
);
const startPosition = deserializeCodeElementPosition(
proofStep.range.start
logger.debug(
`Successfully retrieved target goal at point: "${goal.ty}" at ${startPosition}, "${serializedParsedFile.filePath}"`
);
if (goals.err) {
const goal = goals.val;
const stack = goal.stack === undefined ? "" : `\n${goal.stack}`;
logger.error(
`Failed to retrieve target goal at point: "${goal.message}" at ${startPosition}, "${serializedParsedFile.filePath}"${stack}`
);
throw goal;
} else {
const goal = coqLspClient.getFirstGoalOrThrow(goals);
logger.debug(
`Successfully retrieved target goal at point: "${goal.ty}" at ${startPosition}, "${serializedParsedFile.filePath}"`
);
serializedGoal = serializeGoal(goal);
}
return serializeGoal(goal);
} catch (err) {
const coqLspError = asErrorOrRethrow(err) as CoqLspError;
const stack =
coqLspError.stack === undefined ? "" : `\n${coqLspError.stack}`;
logger.error(
`Failed to retrieve target goal at point: "${coqLspError.message}" at ${startPosition}, "${serializedParsedFile.filePath}"${stack}`
);
throw coqLspError;
}

return {
theoremName: theoremName,
targetType: targetType,
goalToProve: serializedGoal,
positionRange: proofStep.range,
};
}
}
Loading