Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.200.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* Runtime-async sequences allow awaits inside `try/with` bodies, filters and handlers, and reject overlapping `MoveNextAsync` calls. ([PR #20655](https://github.com/dotnet/fsharp/pull/20655))
* F# Interactive gains a JSON-RPC server mode, `--fsi-server-jsonrpc:<pipe name>`, in which a host submits interactions over a named pipe and receives structured results — diagnostics with positions, escaping exceptions, the values each interaction bound, and the session's own process id — instead of recovering them by looking for a `SERVER-PROMPT>` marker in the output text. Program output continues to flow through the redirected console streams. The pipe admits only the user running the session; `--fsi-server-client-pid:<pid>` names the host process whose exit ends the session. `FsiEvaluationSession` exposes both options as `JsonRpcServerPipeName` and `JsonRpcClientProcessId`. The mode is part of the .NET fsi only. ([PR #20396](https://github.com/dotnet/fsharp/pull/20396))
* Include individual active-pattern cases from unopened modules in pattern completion. ([PR #20719](https://github.com/dotnet/fsharp/pull/20719))
* Add `ConditionalDefines` to `FSharpProjectSnapshot` and `ProjectConfig`, matching `FSharpParsingOptions.ConditionalDefines` for the same options: the `--define`/`-d` symbols of `OtherOptions` and the implied `COMPILED` or `INTERACTIVE`. ([PR #TBD](https://github.com/dotnet/fsharp/pull/TBD))
* Add `LangVersionText` to `FSharpProjectSnapshot` and `ProjectConfig`, matching `FSharpParsingOptions.LangVersionText` for the same options: the last `--langversion` in `OtherOptions` that the compiler accepts, otherwise `default`. ([PR #TBD](https://github.com/dotnet/fsharp/pull/TBD))

### Fixed

Expand Down
92 changes: 47 additions & 45 deletions src/Compiler/Driver/CompilerOptions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,41 @@ let DumpCompilerOptionBlocks blocks =
let isSlashOpt (opt: string) =
opt[0] = '/' && (opt.Length = 1 || not (opt[1..].Contains "/"))

// returns a tuple - the option minus switchchars, the option tokenand the option argument string
let ParseCompilerOption (option: string) =

// Get option arguments, I.e everything following first:
let opts = option.Split([| ':' |])
let optArgs = String.Join(":", opts[1..])

let opt =
if String.IsNullOrEmpty(option) then
""
// if it doesn't start with a '-' or '/', reject outright
elif option[0] <> '-' && option[0] <> '/' then
""
elif option <> "--" then
// is it an abbreviated or MSFT-style option?
// if so, strip the first character and move on with your life
// Weirdly a -- option can't have only a 1 character name
if option.Length = 2 || isSlashOpt option then
option[1..]
elif option.Length >= 3 && option[2] = ':' then
option[1..]
elif option.StartsWithOrdinal("--") then
match option.Length with
| l when l >= 4 && option[3] = ':' -> ""
| l when l > 3 -> option[2..]
| _ -> ""
else
""
else
option

// grab the option token
let token = opt.Split([| ':' |])[0]
opt, token, optArgs

module ResponseFile =

type ResponseFileData = ResponseFileLine list
Expand Down Expand Up @@ -260,41 +295,6 @@ let ParseCompilerOptions (collectOtherArgument: string -> unit, blocks: Compiler

let specs = List.collect GetOptionsOfBlock blocks

// returns a tuple - the option minus switchchars, the option tokenand the option argument string
let parseOption (option: string) =

// Get option arguments, I.e everything following first:
let opts = option.Split([| ':' |])
let optArgs = String.Join(":", opts[1..])

let opt =
if String.IsNullOrEmpty(option) then
""
// if it doesn't start with a '-' or '/', reject outright
elif option[0] <> '-' && option[0] <> '/' then
""
elif option <> "--" then
// is it an abbreviated or MSFT-style option?
// if so, strip the first character and move on with your life
// Weirdly a -- option can't have only a 1 character name
if option.Length = 2 || isSlashOpt option then
option[1..]
elif option.Length >= 3 && option[2] = ':' then
option[1..]
elif option.StartsWithOrdinal("--") then
match option.Length with
| l when l >= 4 && option[3] = ':' -> ""
| l when l > 3 -> option[2..]
| _ -> ""
else
""
else
option

// grab the option token
let token = opt.Split([| ':' |])[0]
opt, token, optArgs

let getOptionArg compilerOption (argString: string) =
if String.IsNullOrEmpty(argString) then
errorR (Error(FSComp.SR.buildOptionRequiresParameter (compilerOptionUsage compilerOption), rangeCmdArgs))
Expand Down Expand Up @@ -360,7 +360,7 @@ let ParseCompilerOptions (collectOtherArgument: string -> unit, blocks: Compiler

processArg (responseFileOptions @ t)
| opt :: t ->
let option, optToken, argString = parseOption opt
let option, optToken, argString = ParseCompilerOption opt

let reportDeprecatedOption errOpt =
match errOpt with
Expand Down Expand Up @@ -1136,15 +1136,15 @@ let GetLanguageVersions () =
}
|> String.concat Environment.NewLine

let setLanguageVersion (specifiedVersion: string) =
let ParseLanguageVersion (specifiedVersion: string) =
if specifiedVersion.ToUpperInvariant() = "PREVIEW" then
()
Ok(LanguageVersion(specifiedVersion))
elif not (LanguageVersion.ContainsVersion specifiedVersion) then
error (Error(FSComp.SR.optsUnrecognizedLanguageVersion specifiedVersion, rangeCmdArgs))
Result.Error(Error(FSComp.SR.optsUnrecognizedLanguageVersion specifiedVersion, rangeCmdArgs))
elif not (LanguageVersion.IsVersionSupported specifiedVersion) then
error (Error(FSComp.SR.optsLangVersionOutOfSupport (specifiedVersion, "10.0"), rangeCmdArgs))

LanguageVersion(specifiedVersion)
Result.Error(Error(FSComp.SR.optsLangVersionOutOfSupport (specifiedVersion, "10.0"), rangeCmdArgs))
else
Ok(LanguageVersion(specifiedVersion))

let languageFlags tcConfigB =
[
Expand All @@ -1168,9 +1168,11 @@ let languageFlags tcConfigB =
"langversion",
tagLangVersionValues,
OptionString(fun switch ->
let newVersion = setLanguageVersion switch
// Preserve disabled features when updating version
tcConfigB.langVersion <- newVersion.WithDisabledFeatures(Set.toArray tcConfigB.disabledLanguageFeatures)),
match ParseLanguageVersion switch with
| Ok newVersion ->
// Preserve disabled features when updating version
tcConfigB.langVersion <- newVersion.WithDisabledFeatures(Set.toArray tcConfigB.disabledLanguageFeatures)
| Result.Error e -> error e),
None,
Some(FSComp.SR.optsSetLangVersion ())
)
Expand Down
8 changes: 8 additions & 0 deletions src/Compiler/Driver/CompilerOptions.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module internal FSharp.Compiler.CompilerOptions
open System
open FSharp.Compiler.CompilerConfig
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.Features

// For command-line options that can be suffixed with +/-
[<RequireQualifiedAccess>]
Expand Down Expand Up @@ -49,6 +50,13 @@ val DumpCompilerOptionBlocks: CompilerOptionBlock list -> unit // for QA

val FilterCompilerOptionBlock: (CompilerOption -> bool) -> CompilerOptionBlock -> CompilerOptionBlock

/// Split a single command-line argument into the option without switch chars, the option token and the option argument.
/// The token is empty when the argument is not an option.
val ParseCompilerOption: option: string -> string * string * string

/// The language version --langversion selects for the given text, or the error it reports when the version is not accepted.
val ParseLanguageVersion: specifiedVersion: string -> Result<LanguageVersion, exn>

/// Parse and process a set of compiler options
val ParseCompilerOptions: (string -> unit) * CompilerOptionBlock list * string list -> unit

Expand Down
34 changes: 34 additions & 0 deletions src/Compiler/Service/FSharpProjectSnapshot.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module FSharp.Compiler.CodeAnalysis.ProjectSnapshot
open System
open System.Collections.Generic
open System.IO
open FSharp.Compiler.CompilerOptions
open FSharp.Compiler.Features
open FSharp.Compiler.IO
open Internal.Utilities.Library
open Internal.Utilities.Library.Extras
Expand Down Expand Up @@ -64,6 +66,27 @@ module internal Helpers =
|> Seq.tryFind (fun (x: string) -> x.StartsWith("-o:"))
|> Option.map (fun x -> x.Substring(3))

/// Mirrors the TcConfigBuilder.conditionalDefines produced from the given options: implicit define first, then each define prepended.
let findConditionalDefines (isInteractive: bool) (options: string seq) =
let implicitDefine = if isInteractive then "INTERACTIVE" else "COMPILED"

([ implicitDefine ], options)
||> Seq.fold (fun defines option ->
match ParseCompilerOption option with
| _, ("define" | "d"), define when define <> "" -> define :: defines
| _ -> defines)

/// Mirrors the TcConfigBuilder.langVersion produced from the given options: the last --langversion the compiler accepts, otherwise the default.
let findLangVersion (options: string seq) =
(LanguageVersion.Default, options)
||> Seq.fold (fun langVersion option ->
match ParseCompilerOption option with
| _, "langversion", version ->
match ParseLanguageVersion version with
| Ok newVersion -> newVersion
| Result.Error _ -> langVersion
| _ -> langVersion)

/// A snapshot of an F# source file.
[<Experimental("This FCS API is experimental and subject to change.")>]
type FSharpFileSnapshot(FileName: string, Version: string, GetSource: unit -> Task<ISourceTextNew>) =
Expand Down Expand Up @@ -257,6 +280,8 @@ type internal ProjectSnapshotBase<'T when 'T :> IFileSnapshot>
member _.Identifier = projectConfig.Identifier
member _.ReferencesOnDisk = projectConfig.ReferencesOnDisk
member _.OtherOptions = projectConfig.OtherOptions
member _.ConditionalDefines = projectConfig.ConditionalDefines
member _.LangVersionText = projectConfig.LangVersionText
member _.ReferencedProjects = referencedProjects

member _.IsIncompleteTypeCheckEnvironment =
Expand Down Expand Up @@ -424,6 +449,11 @@ and [<Experimental("This FCS API is experimental and subject to change.")>] Proj
((projectFileName, outputFileNameValue.Value |> Option.defaultValue "")
|> FSharpProjectIdentifier)

let conditionalDefines =
lazy (findConditionalDefines useScriptResolutionRules otherOptions)

let langVersionText = lazy (findLangVersion otherOptions).VersionText

new
(
projectFileName: string,
Expand Down Expand Up @@ -473,6 +503,8 @@ and [<Experimental("This FCS API is experimental and subject to change.")>] Proj
member _.ProjectId = projectId
member _.ReferencesOnDisk = referencesOnDisk
member _.OtherOptions = otherOptions
member _.ConditionalDefines = conditionalDefines.Value
member _.LangVersionText = langVersionText.Value

member _.IsIncompleteTypeCheckEnvironment = isIncompleteTypeCheckEnvironment
member _.UseScriptResolutionRules = useScriptResolutionRules
Expand Down Expand Up @@ -596,6 +628,8 @@ and [<Experimental("This FCS API is experimental and subject to change.")>] FSha
member _.SourceFiles = projectSnapshot.SourceFiles
member _.ReferencesOnDisk = projectSnapshot.ReferencesOnDisk
member _.OtherOptions = projectSnapshot.OtherOptions
member _.ConditionalDefines = projectSnapshot.ConditionalDefines
member _.LangVersionText = projectSnapshot.LangVersionText
member _.ReferencedProjects = projectSnapshot.ReferencedProjects

member _.IsIncompleteTypeCheckEnvironment =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,44 @@ module FSharpChecker.ProjectSnapshot

open Xunit
open System
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.CodeAnalysis.ProjectSnapshot

#nowarn 57

[<Theory>]
[<InlineData(false)>]
[<InlineData(true)>]
let ``ConditionalDefines matches FSharpParsingOptions`` (isInteractive: bool) =
let otherOptions =
[ "--define:A"; "-d:B"; "/define:C"; "/d:D"; "--debug+"; "-o:out.dll"; "--define:E:F"; "--define:"; "-define:G"; "--d:H"; "define:I" ]

let projectConfig =
ProjectConfig("Dummy.fsproj", None, [], otherOptions, useScriptResolutionRules = isInteractive)

let parsingOptions, _ =
FSharpChecker.Create().GetParsingOptionsFromCommandLineArgs(otherOptions, isInteractive = isInteractive)

Assert.Equal<string list>(parsingOptions.ConditionalDefines, projectConfig.ConditionalDefines)

[<Theory>]
[<InlineData("")>]
[<InlineData("--langversion:8.0")>]
[<InlineData("-d:X --langversion:preview")>]
[<InlineData("--langversion:9.0 /langversion:LATEST")>]
[<InlineData("--langversion:4.7")>]
[<InlineData("--langversion:foo")>]
[<InlineData("--langversion:")>]
[<InlineData("-langversion:9.0")>]
let ``LangVersionText matches FSharpParsingOptions`` (options: string) =
let otherOptions = options.Split([| ' ' |], StringSplitOptions.RemoveEmptyEntries) |> Array.toList

let projectConfig = ProjectConfig("Dummy.fsproj", None, [], otherOptions)

let parsingOptions, _ =
FSharpChecker.Create().GetParsingOptionsFromCommandLineArgs(otherOptions)

Assert.Equal(parsingOptions.LangVersionText, projectConfig.LangVersionText)

// TODO: restore tests

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2505,7 +2505,9 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FS
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot] get_ReferencedProjects()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk] ReferencesOnDisk
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk] get_ReferencesOnDisk()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] ConditionalDefines
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] OtherOptions
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_ConditionalDefines()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_OtherOptions()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]] OriginalLoadReferences
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]] get_OriginalLoadReferences()
Expand All @@ -2525,8 +2527,10 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: ProjectConfi
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.DateTime LoadTime
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.DateTime get_LoadTime()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String LangVersionText
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String ProjectFileName
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_Label()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_LangVersionText()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_ProjectFileName()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_snapshot()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot snapshot
Expand Down Expand Up @@ -2581,8 +2585,10 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: FSharpProjectIdentif
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk] ReferencesOnDisk
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk] get_ReferencesOnDisk()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[System.String] CommandLineOptions
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[System.String] ConditionalDefines
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[System.String] OtherOptions
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_CommandLineOptions()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_ConditionalDefines()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_OtherOptions()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]] OriginalLoadReferences
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]] get_OriginalLoadReferences()
Expand All @@ -2597,9 +2603,11 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Microsoft.FSharp.Cor
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.DateTime LoadTime
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.DateTime get_LoadTime()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.String Label
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.String LangVersionText
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.String ProjectDirectory
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.String ProjectFileName
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.String get_Label()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.String get_LangVersionText()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.String get_ProjectDirectory()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: System.String get_ProjectFileName()
FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ProjectConfig: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], System.Collections.Generic.IEnumerable`1[System.String], System.Collections.Generic.IEnumerable`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String])
Expand Down
Loading