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

Draft
wants to merge 5 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: New
Development

Successfully merging this pull request may close these issues.

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