Skip to content

Support --typecheck-only for fsi run (just typecheck, no execution) #18686

@T-Gro

Description

@T-Gro

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.

Metadata

Metadata

Assignees

Projects

Status

New

Relationships

None yet

Development

No branches or pull requests

Issue actions