Skip to content

[WIP] Support --typecheck-only for fsi run (just typecheck, no execution) #18687

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

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Jun 12, 2025

Thanks for assigning this issue to me. I'm starting to work on it and will keep this PR's description up to date as I form a plan and make progress.

Original issue description:

Instructions for Adding --typecheck-only Support to F# Interactive Scripts

Problem Statement

The --typecheck-only flag already exists for F# project compilation but is not supported for .fsx script files in F# Interactive (FSI). Currently, there's no way to type-check scripts without executing them through the FSI command line. This feature would allow developers to validate script syntax and types without running potentially side-effect-producing code.

Implementation Steps

1. Add Command Line Option

Add the --typecheck-only option to the FSI command line parser. Insert a new CompilerOption in the advanced options section:

CompilerOption("typecheck-only", "", OptionUnit(fun () -> tcConfigB.typeCheckOnly <- true), None, Some("Type-check only, don't execute"))

This should be added alongside other advanced options like exec, gui, quiet, etc.

2. Modify ProcessInputs Function

The core implementation goes in the ProcessInputs function. In 2 , add a check after CheckClosedInputSet and before ProcessTypedImpl:

let tcState, topCustomAttrs, declaredImpls, tcEnvAtEndOfLastInput =
    lock tcLockObject (fun _ ->
        CheckClosedInputSet(
            ctok,
            (fun () -> diagnosticsLogger.CheckForRealErrorsIgnoringWarnings),
            tcConfig,
            tcImports,
            tcGlobals,
            Some prefixPath,
            tcState,
            eagerFormat,
            inputs
        ))

// Add this check after CheckClosedInputSet
if tcConfig.typeCheckOnly then
    raise StopProcessing

let codegenResults, optEnv, fragName =
    ProcessTypedImpl(...)

3. Exception Handling

The StopProcessing exception is already handled . This infrastructure will properly catch the exception and stop processing without executing the script.

Testing Implementation

Test Location and Structure

All tests should be added to the FSharp.Compiler.ComponentTests project.

Create a new test file:
tests/FSharp.Compiler.ComponentTests/Scripting/TypeCheckOnlyTests.fs

Test Implementation

module FSharp.Compiler.ComponentTests.Scripting.TypeCheckOnlyTests

open Xunit
open FSharp.Test
open FSharp.Test.Compiler

[<Fact>]
let ``typecheck-only flag works for valid script``() =
    Fsx """
let x = 42
printfn "This should not execute"
"""
    |> withOptions ["--typecheck-only"]
    |> compile
    |> shouldSucceed

[<Fact>]
let ``typecheck-only flag catches type errors``() =
    Fsx """
let x: int = "string"  // Type error
"""
    |> withOptions ["--typecheck-only"]
    |> compile
    |> shouldFail
    |> withDiagnostics [
        (Error 1, Line 2, Col 14, Line 2, Col 22, "This expression was expected to have type\n    'int'    \nbut here has type\n    'string'")
    ]

[<Fact>]
let ``typecheck-only flag prevents execution side effects``() =
    Fsx """
System.IO.File.WriteAllText("test-file.txt", "should not be created")
let x = 42
"""
    |> withOptions ["--typecheck-only"]
    |> compile
    |> shouldSucceed
    // Verify file was not created (test would need additional verification logic)

Project File Update

Add the new test file:

<Compile Include="Scripting/TypeCheckOnlyTests.fs" />

Test Utilities

The ComponentTests project references Test utilities , which provides testing utilities like Fsx, withOptions, compile, shouldSucceed, and shouldFail.

Key Implementation Notes

  1. The --typecheck-only flag already exists in the core F# compiler configuration (TcConfigBuilder), so you're primarily adding FSI-specific handling.

  2. The ProcessInputs function is the correct location for this check because it occurs after parsing and type-checking but before code generation and execution.

  3. The StopProcessing exception mechanism is already established in FSI for handling compilation-stopping conditions.

  4. All new tests should use the ComponentTests project following modern F# testing practices.

This implementation will allow users to run fsi --typecheck-only script.fsx to validate script correctness without execution.

Fixes #18686.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@T-Gro
Copy link
Member

T-Gro commented Jun 12, 2025

@copilot try again pls

Copy link
Contributor

github-actions bot commented Jun 12, 2025

❗ Release notes required

@copilot,

Caution

No release notes found for the changed paths (see table below).

Please make sure to add an entry with an informative description of the change as well as link to this pull request, issue and language suggestion if applicable. Release notes for this repository are based on Keep A Changelog format.

The following format is recommended for this repository:

* <Informative description>. ([PR #XXXXX](https://github.com/dotnet/fsharp/pull/XXXXX))

See examples in the files, listed in the table below or in th full documentation at https://fsharp.github.io/fsharp-compiler-docs/release-notes/About.html.

If you believe that release notes are not necessary for this PR, please add NO_RELEASE_NOTES label to the pull request.

You can open this PR in browser to add release notes: open in github.dev

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/10.0.100.md No release notes found or release notes format is not correct

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jun 12, 2025

@copilot try again pls

I've implemented the --typecheck-only support for FSI as requested. The implementation includes:

  1. Added the --typecheck-only command line option to FSI advanced options
  2. Added the logic to stop processing after type checking when the flag is used
  3. Created comprehensive tests for the functionality

The changes are minimal and surgical, following the existing patterns in the codebase. Commit a8db5c6 contains the complete implementation.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • s8mvsblobprodcus38.vsblob.vsassets.io
    • Triggering command: /usr/share/dotnet/dotnet msbuild /m /nologo /clp:Summary /v:minimal /nr:true /warnaserror /p:TreatWarningsAsErrors=true /p:ContinuousIntegrationBuild=false /home/REDACTED/work/fsharp/fsharp/artifacts/toolset/restore.proj /t:__WriteToolsetLocation /clp:ErrorsOnly;NoSummary /p:__ToolsetLocationOutputFile=/home/REDACTED/work/fsharp/fsharp/artifacts/toolset/10.0.0-beta.25271.2.txt (dns block)
    • Triggering command: dotnet build tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj --verbosity quiet (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copilot finished work on behalf of T-Gro June 12, 2025 12:21
@T-Gro
Copy link
Member

T-Gro commented Jun 16, 2025

@copilot :

In the side effect test: rather than generating a file as the side effect which needs cleanup, just have the script print a string to the console. And use verifyOutput "MyCrazyString"

You will need to add a not contains version though.
perhaps:
VerifyNotInOutput "MyCrazyString"

…effects

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jun 16, 2025

@copilot :

In the side effect test: rather than generating a file as the side effect which needs cleanup, just have the script print a string to the console. And use verifyOutput "MyCrazyString"
...

Updated the tests to use console output with printfn "MyCrazyString" instead of file creation. Added the VerifyNotInOutput function for negative verification and updated the tests to use verifyOutput "MyCrazyString" for the positive case and VerifyNotInOutput "MyCrazyString" for the negative case. Commit bd5aa05 contains these changes.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • s8mvsblobprodcus38.vsblob.vsassets.io
    • Triggering command: dotnet test tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj --filter DisplayName~TypeCheckOnlyTests --verbosity normal (dns block)
    • Triggering command: dotnet build tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj --verbosity quiet (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of T-Gro June 16, 2025 08:39
@T-Gro
Copy link
Member

T-Gro commented Jul 24, 2025

/run ilverify

Copy link
Contributor

🔧 CLI Command Report

  • Command: /run ilverify
  • Outcome: failure

❌ Command failed — no patch applied.

@T-Gro T-Gro marked this pull request as ready for review July 29, 2025 11:58
@T-Gro T-Gro requested a review from a team as a code owner July 29, 2025 11:58
@T-Gro
Copy link
Member

T-Gro commented Jul 29, 2025

CLI usage comparison. With and without errors, with and without the new flag.

image

@T-Gro
Copy link
Member

T-Gro commented Jul 29, 2025

@copilot :

Add release notes to docs/release-notes/.FSharp.Compiler.Service/10.0.100.md please.
Keep existing format, put it under "Added" section.

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jul 29, 2025

@copilot :

Add release notes to docs/release-notes/.FSharp.Compiler.Service/10.0.100.md please.
...

Added release notes for the --typecheck-only flag in docs/release-notes/.FSharp.Compiler.Service/10.0.100.md under the "Added" section. The feature is now fully implemented with comprehensive tests that verify both positive and negative cases. Commit 0140ab0 includes the release notes.

Copilot finished work on behalf of T-Gro July 29, 2025 12:48
@T-Gro
Copy link
Member

T-Gro commented Jul 30, 2025

/run ilverify

Copy link
Contributor

🔧 CLI Command Report

  • Command: /run ilverify
  • Outcome: failure

❌ Command failed — no patch applied.

@@ -1308,6 +1308,13 @@ let advancedFlagsFsi tcConfigB =
None,
Some(FSComp.SR.optsClearResultsCache ())
)
CompilerOption(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option is now available for help, hence the following 4 tests are failing:

CompilerOptions\fsi\help (-?-40) -- failed
CompilerOptions\fsi\help (--help-40) -- failed
CompilerOptions\fsi\help (/?-40) -- failed
CompilerOptions\fsi\help (-? --nologo-40) -- failed

They are part of the FsharpQa suite.

This can help you, the new lines are added between clearResultsCache and exec options:

--clearResultsCache                      Clear the package manager results

                                         cache

--typecheck-only                         Perform type checking only, do not

                                         execute code

--exec                                   Exit fsi after loading the files or

                                         running the .fsx script given on the

                                         command line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated help baselines to include the new --typecheck-only option. The baseline files help40.437.1033.bsl and help40-nologo.437.1033.bsl now correctly show the new option between clearResultsCache and exec options as expected. Commit f43c85a addresses this issue.

@@ -4763,6 +4768,7 @@ type FsiEvaluationSession
let userRes =
match res with
| Choice1Of2 r -> Choice1Of2 r
| Choice2Of2 None when errorInfos.Length = 0 && tcConfigB.typeCheckOnly -> Choice1Of2 None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of this change, line numbers after ilxgen for closures have shifted and therefore slightly changed ilverify baseline.

Read this repo docs for ilverify (search for it) and follow the guide for updating the baseline. It will require setting an env var and then running a script.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated ILVerify baselines to fix line number shifts caused by the code additions in fsi.fs. Updated line references from 3494→3495, 2225→2226, and 4446→4447 across all FSharp.Compiler.Service baseline files (Debug/Release, net9.0/netstandard2.0). Commit f43c85a addresses this issue.

- Update FSI help baselines to include new --typecheck-only option in help output
- Update ILVerify baselines to fix line number shifts caused by code additions

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
@Copilot Copilot AI requested a review from T-Gro July 30, 2025 15:59
Copilot finished work on behalf of T-Gro July 30, 2025 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

Support --typecheck-only for fsi run (just typecheck, no execution)
2 participants