diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 08c638660f1..083002d6543 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -90,6 +90,7 @@ * Warn FS3888 when a compiler-semantic attribute on a value/member or type/module is present in the `.fs` but missing from the `.fsi`. Such attributes were previously ignored at the consumer side. Under the `ErrorOnMissingSignatureAttribute` preview language feature, FS3888 is an error. ([Issue #19560](https://github.com/dotnet/fsharp/issues/19560), [PR #19880](https://github.com/dotnet/fsharp/pull/19880)) * Emit debug points at a stack-empty position ([PR #19877](https://github.com/dotnet/fsharp/pull/19877)) * Fix spurious XmlDoc warnings (unknown parameter / no documentation for parameter) under `--warnon:3390` when a get/set property documents the full parameter set across both accessors. ([Issue #13684](https://github.com/dotnet/fsharp/issues/13684), [PR #19884](https://github.com/dotnet/fsharp/pull/19884)) +* Stop F# Interactive from mutating script arguments that follow `--`. Abbreviated flags like `-d`, `-r`, `-I` after the `--` separator are no longer colon-joined with their next token in `fsi.CommandLineArgs`. ([Issue #10819](https://github.com/dotnet/fsharp/issues/10819), [PR #19926](https://github.com/dotnet/fsharp/pull/19926)) * Fix FSI pretty printing to distinguish anonymous records (`{| ... |}`) from nominal records (`{ ... }`). ([Issue #6116](https://github.com/dotnet/fsharp/issues/6116), [PR #19919](https://github.com/dotnet/fsharp/pull/19919)) * Fix dot-completion after indexed expressions (`a.[0].Data.`, `a[0].Data.`, `[1;2].Length.`) returning unrelated global completions instead of expression-typings members. ([Issue #4966](https://github.com/dotnet/fsharp/issues/4966), [PR #19934](https://github.com/dotnet/fsharp/pull/19934)) * Quotations of `match s with "" -> _` no longer leak the `s <> null && s.Length = 0` lowering; the empty-string optimization moved from pattern-match compilation to the optimizer so quoted expressions keep `op_Equality(s, "")`. ([Issue #19873](https://github.com/dotnet/fsharp/issues/19873)) diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 30801263752..7a2f353db0b 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -1225,7 +1225,20 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s @ fsiUsageSuffix tcConfigB let abbrevArgs = GetAbbrevFlagSet tcConfigB false - ParseCompilerOptions(collect, fsiCompilerOptions, List.tail (PostProcessCompilerArgs abbrevArgs argv)) + // PostProcessCompilerArgs rewrites abbreviated flags like `-d 5` to `-d:5`. + // We must NOT apply that rewrite to user-script arguments that follow `--`, + // otherwise fsi.CommandLineArgs leaks the rewrite to scripts (see #10819). + // Split argv at the first `--`, post-process only the compiler-args prefix, + // and pass the suffix (including the `--` separator itself) through unmodified. + let processedArgs = + match Array.tryFindIndex (fun (a: string) -> a = "--") argv with + | Some idx -> + let prefix = argv[0 .. idx - 1] + let suffix = argv[idx..] + PostProcessCompilerArgs abbrevArgs prefix @ List.ofArray suffix + | None -> PostProcessCompilerArgs abbrevArgs argv + + ParseCompilerOptions(collect, fsiCompilerOptions, List.tail processedArgs) with e -> stopProcessingRecovery e range0 failwithf "Error creating evaluation session: %A" e diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsi/FsiCommandLineArgsTests.fs b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsi/FsiCommandLineArgsTests.fs new file mode 100644 index 00000000000..10754e1684c --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsi/FsiCommandLineArgsTests.fs @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace CompilerOptions.Fsi + +open System +open System.IO +open Xunit +open FSharp.Test +open FSharp.Test.Compiler + +/// Regression tests for https://github.com/dotnet/fsharp/issues/10819 +/// fsi.CommandLineArgs must preserve every token after `--` byte-for-byte; +/// in particular abbreviated flags like -d / -r / -I that follow `--` must +/// NOT be colon-joined with their next argument. +module FsiCommandLineArgsTests = + + let private writeProbeScript () : string = + // Prints one ARG= line per element of fsi.CommandLineArgs so the + // test can parse exact contents from stdout. A leading empty `printfn` + // ensures the first ARG= line is never prefixed by an FSI `> ` prompt + // (which only matters when the probe runs interactively via --use, + // not when it is invoked as the script-file argument directly). + let body = """ +printfn "" +for a in fsi.CommandLineArgs do + printfn "ARG=%s" a +""" + let path = + Path.Combine( + Path.GetTempPath(), + sprintf "fsi_cmdline_%s.fsx" (Guid.NewGuid().ToString("N"))) + File.WriteAllText(path, body) + path + + let private parseArgsFromStdOut (stdout: string) : string list = + stdout.Split([| '\r'; '\n' |], StringSplitOptions.RemoveEmptyEntries) + |> Array.choose (fun line -> + if line.StartsWith("ARG=") then Some (line.Substring(4)) else None) + |> Array.toList + + /// Run fsi