diff --git a/eng/Build.ps1 b/eng/Build.ps1 index 034ea1aaa6e..6e3d12f0e0a 100644 --- a/eng/Build.ps1 +++ b/eng/Build.ps1 @@ -46,6 +46,7 @@ param ( [switch]$warnAsError = $true, [switch][Alias('test')]$testDesktop, [switch]$testCoreClr, + [switch]$testFSharpCompiler, [switch]$testFSharpQA, [switch]$testFSharpCore, [switch]$testVs, @@ -77,6 +78,7 @@ function Print-Usage() { Write-Host " -testAll Run all tests" Write-Host " -testDesktop Run tests against full .NET Framework" Write-Host " -testCoreClr Run tests against CoreCLR" + Write-Host " -testFSharpCompiler Run F# Compiler unit tests" Write-Host " -testFSharpQA Run F# Cambridge tests" Write-Host " -testFSharpCore Run FSharpCore unit tests" Write-Host " -testVs Run F# editor unit tests" @@ -279,16 +281,16 @@ try { } if ($testFSharpCore) { - Write-Host "Environment Variables" - Get-Childitem Env: TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $desktopTargetFramework TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $coreclrTargetFramework } + if ($testFSharpCompiler) { + TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.UnitTests\FSharp.Compiler.UnitTests.fsproj" -targetFramework $desktopTargetFramework + TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.UnitTests\FSharp.Compiler.UnitTests.fsproj" -targetFramework $coreclrTargetFramework + } if ($testVs) { - Write-Host "Environment Variables" - Get-Childitem Env: TestUsingNUnit -testProject "$RepoRoot\vsintegration\tests\GetTypesVS.UnitTests\GetTypesVS.UnitTests.fsproj" -targetFramework $desktopTargetFramework TestUsingNUnit -testProject "$RepoRoot\vsintegration\tests\UnitTests\VisualFSharp.UnitTests.fsproj" -targetFramework $desktopTargetFramework } diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index 67189b402cb..30a2e69df05 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -2141,6 +2141,7 @@ type TcConfigBuilder = /// When false FSI will lock referenced assemblies requiring process restart, false = disable Shadow Copy false (*default*) mutable shadowCopyReferences: bool + mutable useSdkRefs: bool /// A function to call to try to get an object that acts as a snapshot of the metadata section of a .NET binary, /// and from which we can read the metadata. Only used when metadataOnly=true. @@ -2280,6 +2281,7 @@ type TcConfigBuilder = exename = None copyFSharpCore = CopyFSharpCoreFlag.No shadowCopyReferences = false + useSdkRefs = true tryGetMetadataSnapshot = (fun _ -> None) internalTestSpanStackReferring = false noConditionalErasure = false @@ -2747,6 +2749,7 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member x.emitDebugInfoInQuotations = data.emitDebugInfoInQuotations member x.copyFSharpCore = data.copyFSharpCore member x.shadowCopyReferences = data.shadowCopyReferences + member x.useSdkRefs = data.useSdkRefs member x.tryGetMetadataSnapshot = data.tryGetMetadataSnapshot member x.internalTestSpanStackReferring = data.internalTestSpanStackReferring member x.noConditionalErasure = data.noConditionalErasure @@ -2795,6 +2798,11 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = if Directory.Exists runtimeRootWPF then yield runtimeRootWPF // PresentationCore.dll is in C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF + match getFrameworkRefsPackDirectory with + | Some path when Directory.Exists(path) -> + yield path + | _ -> () + | ResolutionEnvironment.EditingOrCompilation _ -> #if ENABLE_MONO_SUPPORT if runningOnMono then @@ -2857,13 +2865,14 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = /// /// Returning true may mean that the file is locked and/or placed into the /// 'framework' reference set that is potentially shared across multiple compilations. - member tcConfig.IsSystemAssembly (filename: string) = - try - FileSystem.SafeExists filename && + member tcConfig.IsSystemAssembly (filename: string) = + try + FileSystem.SafeExists filename && ((tcConfig.GetTargetFrameworkDirectories() |> List.exists (fun clrRoot -> clrRoot = Path.GetDirectoryName filename)) || - (systemAssemblies.Contains(fileNameWithoutExtension filename))) + (systemAssemblies.Contains (fileNameWithoutExtension filename)) || + isInReferenceAssemblyPackDirectory filename) with _ -> - false + false // This is not the complete set of search paths, it is just the set // that is special to F# (as compared to MSBuild resolution) @@ -3506,18 +3515,16 @@ type TcAssemblyResolutions(tcConfig: TcConfig, results: AssemblyResolution list, TcConfig.TryResolveLibsUsingMSBuildRules (tcConfig, assemblyList, rangeStartup, ResolveAssemblyReferenceMode.ReportErrors) TcAssemblyResolutions(tcConfig, resolved, unresolved @ knownUnresolved) - - static member GetAllDllReferences (tcConfig: TcConfig) = - [ + static member GetAllDllReferences (tcConfig: TcConfig) = [ let primaryReference = tcConfig.PrimaryAssemblyDllReference() - yield primaryReference + //yield primaryReference if not tcConfig.compilingFslib then yield tcConfig.CoreLibraryDllReference() let assumeDotNetFramework = primaryReference.SimpleAssemblyNameIs("mscorlib") - if tcConfig.framework then - for s in defaultReferencesForScriptsAndOutOfProjectSources assumeDotNetFramework do + if tcConfig.framework then + for s in defaultReferencesForScriptsAndOutOfProjectSources assumeDotNetFramework tcConfig.useSdkRefs do yield AssemblyReference(rangeStartup, (if s.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) then s else s+".dll"), None) if tcConfig.useFsiAuxLib then @@ -4552,8 +4559,14 @@ type TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolu // Note: TcImports are disposable - the caller owns this object and must dispose let frameworkTcImports = new TcImports(tcConfigP, tcResolutions, None, None) - - let primaryAssemblyReference = tcConfig.PrimaryAssemblyDllReference() + + // Fetch the primaryAssembly from the referenced assemblies otherwise + let primaryAssemblyReference = + let path = frameworkDLLs |> List.tryFind(fun dll -> String.Compare(Path.GetFileNameWithoutExtension(dll.resolvedPath), tcConfig.primaryAssembly.Name, StringComparison.OrdinalIgnoreCase) = 0) + match path with + | Some p -> AssemblyReference(range0, p.resolvedPath, None) + | None -> tcConfig.PrimaryAssemblyDllReference() + let primaryAssemblyResolution = frameworkTcImports.ResolveAssemblyReference(ctok, primaryAssemblyReference, ResolveAssemblyReferenceMode.ReportErrors) let! primaryAssem = frameworkTcImports.RegisterAndImportReferencedAssemblies(ctok, primaryAssemblyResolution) let primaryScopeRef = @@ -4568,7 +4581,7 @@ type TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAssemblyResolu let! _assemblies = frameworkTcImports.RegisterAndImportReferencedAssemblies (ctok, tcResolutions.GetAssemblyResolutions()) // These are the DLLs we can search for well-known types - let sysCcus = + let sysCcus = [| for ccu in frameworkTcImports.GetCcusInDeclOrder() do //printfn "found sys ccu %s" ccu.AssemblyName yield ccu |] @@ -4913,8 +4926,8 @@ module private ScriptPreprocessClosure = filename: string, codeContext, useSimpleResolution, useFsiAuxLib, basicReferences, applyCommandLineArgs, - assumeDotNetFramework, tryGetMetadataSnapshot, - reduceMemoryUsage) = + assumeDotNetFramework, useSdkRefs, + tryGetMetadataSnapshot, reduceMemoryUsage) = let projectDir = Path.GetDirectoryName filename let isInteractive = (codeContext = CodeContext.CompilationAndEvaluation) @@ -4929,7 +4942,7 @@ module private ScriptPreprocessClosure = applyCommandLineArgs tcConfigB match basicReferences with - | None -> (basicReferencesForScriptLoadClosure useFsiAuxLib assumeDotNetFramework) |> List.iter(fun f->tcConfigB.AddReferencedAssemblyByPath(range0, f)) // Add script references + | None -> (basicReferencesForScriptLoadClosure useFsiAuxLib useSdkRefs assumeDotNetFramework) |> List.iter(fun f->tcConfigB.AddReferencedAssemblyByPath(range0, f)) // Add script references | Some rs -> for m, r in rs do tcConfigB.AddReferencedAssemblyByPath(m, r) tcConfigB.resolutionEnvironment <- @@ -4942,8 +4955,10 @@ module private ScriptPreprocessClosure = // Indicates that there are some references not in basicReferencesForScriptLoadClosure which should // be added conditionally once the relevant version of mscorlib.dll has been detected. tcConfigB.implicitlyResolveAssemblies <- false + tcConfigB.useSdkRefs <- useSdkRefs + TcConfig.Create(tcConfigB, validate=true) - + let ClosureSourceOfFilename(filename, m, inputCodePage, parseRequired) = try let filename = FileSystem.GetFullPathShim filename @@ -5111,10 +5126,10 @@ module private ScriptPreprocessClosure = /// Given source text, find the full load closure. Used from service.fs, when editing a script file let GetFullClosureOfScriptText - (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, - filename, sourceText, - codeContext, useSimpleResolution, useFsiAuxLib, - lexResourceManager: Lexhelp.LexResourceManager, + (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, + filename, sourceText, codeContext, + useSimpleResolution, useFsiAuxLib, useSdkRefs, + lexResourceManager: Lexhelp.LexResourceManager, applyCommmandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) = @@ -5127,7 +5142,7 @@ module private ScriptPreprocessClosure = CreateScriptTextTcConfig(legacyReferenceResolver, defaultFSharpBinariesDir, filename, codeContext, useSimpleResolution, useFsiAuxLib, None, applyCommmandLineArgs, assumeDotNetFramework, - tryGetMetadataSnapshot, reduceMemoryUsage) + useSdkRefs, tryGetMetadataSnapshot, reduceMemoryUsage) let resolutions0, _unresolvedReferences = GetAssemblyResolutionInformation(ctok, tcConfig) let references0 = resolutions0 |> List.map (fun r->r.originalReference.Range, r.resolvedPath) |> Seq.distinct |> List.ofSeq @@ -5136,7 +5151,8 @@ module private ScriptPreprocessClosure = let tcConfig = CreateScriptTextTcConfig(legacyReferenceResolver, defaultFSharpBinariesDir, filename, codeContext, useSimpleResolution, useFsiAuxLib, Some references0, - applyCommmandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) + applyCommmandLineArgs, assumeDotNetFramework, useSdkRefs, + tryGetMetadataSnapshot, reduceMemoryUsage) let closureSources = [ClosureSource(filename, range0, sourceText, true)] let closureFiles, tcConfig = FindClosureFiles(closureSources, tcConfig, codeContext, lexResourceManager) @@ -5162,15 +5178,15 @@ type LoadClosure with /// A temporary TcConfig is created along the way, is why this routine takes so many arguments. We want to be sure to use exactly the /// same arguments as the rest of the application. static member ComputeClosureOfScriptText - (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, - filename: string, sourceText:ISourceText, codeContext, useSimpleResolution: bool, - useFsiAuxLib, lexResourceManager: Lexhelp.LexResourceManager, - applyCommmandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage): LoadClosure = + (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, + filename: string, sourceText: ISourceText, codeContext, useSimpleResolution: bool, + useFsiAuxLib, useSdkRefs, lexResourceManager: Lexhelp.LexResourceManager, + applyCommmandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse ScriptPreprocessClosure.GetFullClosureOfScriptText - (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, sourceText, - codeContext, useSimpleResolution, useFsiAuxLib, lexResourceManager, + (ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, sourceText, + codeContext, useSimpleResolution, useFsiAuxLib, useSdkRefs, lexResourceManager, applyCommmandLineArgs, assumeDotNetFramework, tryGetMetadataSnapshot, reduceMemoryUsage) /// Analyze a set of script files and find the closure of their references. @@ -5480,4 +5496,4 @@ let TypeCheckClosedInputSet (ctok, checkForErrors, tcConfig, tcImports, tcGlobal // Existing public APIs delegate to newer implementations let GetFSharpCoreLibraryName () = getFSharpCoreLibraryName -let DefaultReferencesForScriptsAndOutOfProjectSources assumeDotNetFramework = defaultReferencesForScriptsAndOutOfProjectSources assumeDotNetFramework +let DefaultReferencesForScriptsAndOutOfProjectSources assumeDotNetFramework = defaultReferencesForScriptsAndOutOfProjectSources assumeDotNetFramework false diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi index c3d88bb4a11..3a2dfba549d 100755 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -361,6 +361,7 @@ type TcConfigBuilder = mutable exename: string option mutable copyFSharpCore: CopyFSharpCoreFlag mutable shadowCopyReferences: bool + mutable useSdkRefs: bool /// A function to call to try to get an object that acts as a snapshot of the metadata section of a .NET binary, /// and from which we can read the metadata. Only used when metadataOnly=true. @@ -371,6 +372,7 @@ type TcConfigBuilder = /// Prevent erasure of conditional attributes and methods so tooling is able analyse them. mutable noConditionalErasure: bool + } static member Initial: TcConfigBuilder @@ -394,11 +396,9 @@ type TcConfigBuilder = member RemoveReferencedAssemblyByPath: range * string -> unit member AddEmbeddedSourceFile: string -> unit member AddEmbeddedResource: string -> unit - - static member SplitCommandLineResourceInfo: string -> string * string * ILResourceAccess + static member SplitCommandLineResourceInfo: string -> string * string * ILResourceAccess - [] // Immutable TcConfig type TcConfig = @@ -531,6 +531,8 @@ type TcConfig = member copyFSharpCore: CopyFSharpCoreFlag member shadowCopyReferences: bool + member useSdkRefs: bool + static member Create: TcConfigBuilder * validate: bool -> TcConfig /// Represents a computation to return a TcConfig. Normally this is just a constant immutable TcConfig, @@ -801,7 +803,7 @@ type LoadClosure = // /// A temporary TcConfig is created along the way, is why this routine takes so many arguments. We want to be sure to use exactly the /// same arguments as the rest of the application. - static member ComputeClosureOfScriptText: CompilationThreadToken * legacyReferenceResolver: ReferenceResolver.Resolver * defaultFSharpBinariesDir: string * filename: string * sourceText: ISourceText * implicitDefines:CodeContext * useSimpleResolution: bool * useFsiAuxLib: bool * lexResourceManager: Lexhelp.LexResourceManager * applyCompilerOptions: (TcConfigBuilder -> unit) * assumeDotNetFramework: bool * tryGetMetadataSnapshot: ILReaderTryGetMetadataSnapshot * reduceMemoryUsage: ReduceMemoryFlag -> LoadClosure + static member ComputeClosureOfScriptText: CompilationThreadToken * legacyReferenceResolver: ReferenceResolver.Resolver * defaultFSharpBinariesDir: string * filename: string * sourceText: ISourceText * implicitDefines:CodeContext * useSimpleResolution: bool * useFsiAuxLib: bool * useSdkRefs: bool * lexResourceManager: Lexhelp.LexResourceManager * applyCompilerOptions: (TcConfigBuilder -> unit) * assumeDotNetFramework: bool * tryGetMetadataSnapshot: ILReaderTryGetMetadataSnapshot * reduceMemoryUsage: ReduceMemoryFlag -> LoadClosure /// Analyze a set of script files and find the closure of their references. The resulting references are then added to the given TcConfig. /// Used from fsi.fs and fsc.fs, for #load and command line. diff --git a/src/fsharp/CompileOptions.fs b/src/fsharp/CompileOptions.fs index e1316708559..b5584f88ee0 100644 --- a/src/fsharp/CompileOptions.fs +++ b/src/fsharp/CompileOptions.fs @@ -442,6 +442,9 @@ let subSystemVersionSwitch (tcConfigB: TcConfigBuilder) (text: string) = | _ -> fail() | _ -> fail() +let SetUseSdkSwitch (tcConfigB: TcConfigBuilder) switch = + tcConfigB.useSdkRefs <- (switch = OptionSwitch.On) + let (++) x s = x @ [s] let SetTarget (tcConfigB: TcConfigBuilder)(s: string) = @@ -544,18 +547,21 @@ let PrintOptionInfo (tcConfigB:TcConfigBuilder) = // OptionBlock: Input files //------------------------- -let inputFileFlagsBoth (tcConfigB : TcConfigBuilder) = - [ CompilerOption("reference", tagFile, OptionString (fun s -> tcConfigB.AddReferencedAssemblyByPath (rangeStartup, s)), None, - Some (FSComp.SR.optsReference()) ) +let inputFileFlagsBoth (tcConfigB: TcConfigBuilder) = + [ CompilerOption("reference", tagFile, OptionString (fun s -> tcConfigB.AddReferencedAssemblyByPath (rangeStartup, s)), None, Some (FSComp.SR.optsReference())) ] -let referenceFlagAbbrev (tcConfigB: TcConfigBuilder) = - CompilerOption("r", tagFile, OptionString (fun s -> tcConfigB.AddReferencedAssemblyByPath (rangeStartup, s)), None, - Some(FSComp.SR.optsShortFormOf("--reference")) ) - -let inputFileFlagsFsi tcConfigB = inputFileFlagsBoth tcConfigB -let inputFileFlagsFsc tcConfigB = inputFileFlagsBoth tcConfigB +let inputFileFlagsFsc tcConfigB = inputFileFlagsBoth tcConfigB + +let inputFileFlagsFsiBase (_tcConfigB: TcConfigBuilder) = +#if NETSTANDARD + [ CompilerOption("usesdkrefs", tagNone, OptionSwitch (SetUseSdkSwitch _tcConfigB), None, Some (FSComp.SR.useSdkRefs())) ] +#else + List.empty +#endif +let inputFileFlagsFsi (tcConfigB: TcConfigBuilder) = + List.concat [ inputFileFlagsBoth tcConfigB; inputFileFlagsFsiBase tcConfigB] // OptionBlock: Errors and warnings //--------------------------------- @@ -825,12 +831,6 @@ let libFlag (tcConfigB: TcConfigBuilder) = OptionStringList (fun s -> tcConfigB.AddIncludePath (rangeStartup, s, tcConfigB.implicitIncludeDir)), None, Some (FSComp.SR.optsLib())) -let libFlagAbbrev (tcConfigB: TcConfigBuilder) = - CompilerOption - ("I", tagDirList, - OptionStringList (fun s -> tcConfigB.AddIncludePath (rangeStartup, s, tcConfigB.implicitIncludeDir)), None, - Some (FSComp.SR.optsShortFormOf("--lib"))) - let codePageFlag (tcConfigB: TcConfigBuilder) = CompilerOption ("codepage", tagInt, @@ -1395,8 +1395,10 @@ let abbreviatedFlagsBoth tcConfigB = CompilerOption("O", tagNone, OptionSwitch (SetOptimizeSwitch tcConfigB), None, Some(FSComp.SR.optsShortFormOf("--optimize[+|-]"))) CompilerOption("g", tagNone, OptionSwitch (SetDebugSwitch tcConfigB None), None, Some(FSComp.SR.optsShortFormOf("--debug"))) CompilerOption("i", tagString, OptionUnit (fun () -> tcConfigB.printSignature <- true), None, Some(FSComp.SR.optsShortFormOf("--sig"))) - referenceFlagAbbrev tcConfigB (* -r *) - libFlagAbbrev tcConfigB (* -I *) + CompilerOption("r", tagFile, OptionString (fun s -> tcConfigB.AddReferencedAssemblyByPath (rangeStartup, s)), + None, Some(FSComp.SR.optsShortFormOf("--reference"))) + CompilerOption("I", tagDirList, OptionStringList (fun s -> tcConfigB.AddIncludePath (rangeStartup, s, tcConfigB.implicitIncludeDir)), + None, Some (FSComp.SR.optsShortFormOf("--lib"))) ] let abbreviatedFlagsFsi tcConfigB = abbreviatedFlagsBoth tcConfigB diff --git a/src/fsharp/DotNetFrameworkDependencies.fs b/src/fsharp/DotNetFrameworkDependencies.fs index 16d9f70f77d..504bde5fa37 100644 --- a/src/fsharp/DotNetFrameworkDependencies.fs +++ b/src/fsharp/DotNetFrameworkDependencies.fs @@ -2,11 +2,11 @@ // Functions to retrieve framework dependencies - module internal FSharp.Compiler.DotNetFrameworkDependencies open System open System.Collections.Generic + open System.Diagnostics open System.IO open System.Reflection @@ -34,6 +34,103 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies None with _ -> None + // Compare nuget version strings + // + // Format: + // ======= + // $(Major).$(Minor).$(Build) [-SomeSuffix] + // Major, Minor, Build collates normally + // Strings without -SomeSuffix collate higher than SomeSuffix, + // SomeSuffix collates using normal alphanumeric rules + // + let deconstructVersion (version:string) = + let version, suffix = + let pos = version.IndexOf("-") + if pos >= 0 then + version.Substring(0, pos), version.Substring(pos + 1) + else version, "" + + let elements = version.Split('.') + if elements.Length < 3 then + struct (0, 0, 0, suffix) + else + struct (Int32.Parse(elements.[0]), Int32.Parse(elements.[1]), Int32.Parse(elements.[2]), suffix) + + let versionCompare c1 c2 = + if c1 = c2 then 0 + else + try + let struct (major1, minor1, build1, suffix1 ) = deconstructVersion c1 + let struct (major2, minor2, build2, suffix2 ) = deconstructVersion c2 + let v = major1 - major2 + if v <> 0 then v + else + let v = minor1 - minor2 + if v <> 0 then v + else + let v = build1 - build2 + if v <> 0 then v + else + match String.IsNullOrEmpty(suffix1), String.IsNullOrEmpty(suffix2) with + | true, true -> 0 + | true, false -> 1 + | false, true -> -1 + | false, false -> String.Compare(suffix1, suffix2, StringComparison.InvariantCultureIgnoreCase) + with _ -> 0 + + let executionTfm = + let file = + try + let depsJsonPath = Path.ChangeExtension(Assembly.GetEntryAssembly().Location, "deps.json") + File.ReadAllText(depsJsonPath) + with _ -> "" + + let tfmPrefix=".NETCoreApp,Version=v" + let pattern = "\"name\": \"" + tfmPrefix + let startPos = + let startPos = file.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) + if startPos >= 0 then startPos + (pattern.Length) else startPos + + let length = + if startPos >= 0 then + let ep = file.IndexOf("\"", startPos) + if ep >= 0 then ep - startPos else ep + else -1 + match startPos, length with + | -1, _ + | _, -1 -> None + | pos, length -> Some ("netcoreapp" + file.Substring(pos, length)) + + + let getFrameworkRefsPackDirectoryPath = + match executionTfm with + | Some _ -> + let appRefDir = Path.Combine(getFSharpCompilerLocation, "../../../packs/Microsoft.NETCore.App.Ref") + if Directory.Exists(appRefDir) then + Some appRefDir + else + None + | _ -> None + + let isInReferenceAssemblyPackDirectory filename = + match getFrameworkRefsPackDirectoryPath with + | Some appRefDir -> + let path = Path.GetDirectoryName(filename) + path.StartsWith(appRefDir, StringComparison.OrdinalIgnoreCase) + | _ -> false + + let getFrameworkRefsPackDirectory = + match executionTfm, getFrameworkRefsPackDirectoryPath with + | Some tfm, Some appRefDir -> + try + let refDirs = Directory.GetDirectories(appRefDir) + let versionPath = refDirs |> Array.sortWith (versionCompare) |> Array.last + Some(Path.Combine(versionPath, "ref", tfm)) + with | _ -> None + | _ -> None + + + let getDependenciesOf assemblyReferences = let assemblies = new Dictionary() @@ -94,7 +191,7 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies yield "System.Core" yield getDefaultFSharpCoreReference if useFsiAuxLib then yield getFsiLibraryName - + // always include a default reference to System.ValueTuple.dll in scripts and out-of-project sources match getDefaultSystemValueTupleReference() with | None -> () @@ -120,19 +217,38 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies yield "System.Numerics" ] - let fetchPathsForDefaultReferencesForScriptsAndOutOfProjectSources useFsiAuxLib assumeDotNetFramework = - if assumeDotNetFramework then - getDesktopDefaultReferences useFsiAuxLib - else - // Coreclr supports netstandard assemblies only for now - (getDependenciesOf [ - yield Path.Combine(frameworkDir, "netstandard.dll"); - yield getDefaultFSharpCoreReference; - if useFsiAuxLib then yield getFsiLibraryName - ]).Values |> Seq.toList + let fetchPathsForDefaultReferencesForScriptsAndOutOfProjectSources useFsiAuxLib useSdkRefs assumeDotNetFramework = + let results = + if assumeDotNetFramework then + getDesktopDefaultReferences useFsiAuxLib + else + let dependencies = + let getImplementationReferences () = + // Coreclr supports netstandard assemblies only for now + (getDependenciesOf [ + yield Path.Combine(frameworkDir, "netstandard.dll") + yield getDefaultFSharpCoreReference + if useFsiAuxLib then yield getFsiLibraryName + ]).Values |> Seq.toList + + if useSdkRefs then + // Go fetch references + match getFrameworkRefsPackDirectory with + | Some path -> + try [ yield! Directory.GetFiles(path, "*.dll") + yield getDefaultFSharpCoreReference + if useFsiAuxLib then yield getFsiLibraryName + ] + with | _ -> List.empty + | None -> + getImplementationReferences () + else + getImplementationReferences () + dependencies + results - let defaultReferencesForScriptsAndOutOfProjectSources assumeDotNetFramework = - fetchPathsForDefaultReferencesForScriptsAndOutOfProjectSources false assumeDotNetFramework + let defaultReferencesForScriptsAndOutOfProjectSources assumeDotNetFramework useSdkRefs = + fetchPathsForDefaultReferencesForScriptsAndOutOfProjectSources false useSdkRefs assumeDotNetFramework // A set of assemblies to always consider to be system assemblies. A common set of these can be used a shared // resources between projects in the compiler services. Also all assemblies where well-known system types exist @@ -241,5 +357,5 @@ module internal FSharp.Compiler.DotNetFrameworkDependencies ] // The set of references entered into the TcConfigBuilder for scripts prior to computing the load closure. - let basicReferencesForScriptLoadClosure useFsiAuxLib assumeDotNetFramework = - fetchPathsForDefaultReferencesForScriptsAndOutOfProjectSources useFsiAuxLib assumeDotNetFramework + let basicReferencesForScriptLoadClosure useFsiAuxLib useSdkRefs assumeDotNetFramework = + fetchPathsForDefaultReferencesForScriptsAndOutOfProjectSources useFsiAuxLib useSdkRefs assumeDotNetFramework diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 63324554f1c..ae6570ae776 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1458,3 +1458,4 @@ notAFunctionButMaybeDeclaration,"This value is not a function and cannot be appl 3245,tcCopyAndUpdateNeedsRecordType,"The input to a copy-and-update expression that creates an anonymous record must be either an anonymous record or a record" 3300,chkInvalidFunctionParameterType,"The parameter '%s' has an invalid type '%s'. This is not permitted by the rules of Common IL." 3301,chkInvalidFunctionReturnType,"The function or method has an invalid return type '%s'. This is not permitted by the rules of Common IL." +useSdkRefs,"Use reference assemblies for DotNET framework references when available (Enabled by default))." diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 52dc674073e..fc367665d38 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -2432,6 +2432,7 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i do tcConfigB.useFsiAuxLib <- fsi.UseFsiAuxLib #if NETSTANDARD + do tcConfigB.useSdkRefs <- true do tcConfigB.useSimpleResolution <- true do SetTargetProfile tcConfigB "netcore" // always assume System.Runtime codegen #endif diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 177b0287208..6ffeb0b8de4 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -2820,14 +2820,14 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC member bc.ParseAndCheckProject(options, userOpName) = reactor.EnqueueAndAwaitOpAsync(userOpName, "ParseAndCheckProject", options.ProjectFileName, fun ctok -> bc.ParseAndCheckProjectImpl(options, ctok, userOpName)) - member bc.GetProjectOptionsFromScript(filename, sourceText, loadedTimeStamp, otherFlags, useFsiAuxLib: bool option, assumeDotNetFramework: bool option, extraProjectInfo: obj option, optionsStamp: int64 option, userOpName) = + member bc.GetProjectOptionsFromScript(filename, sourceText, loadedTimeStamp, otherFlags, useFsiAuxLib: bool option, useSdkRefs: bool option, assumeDotNetFramework: bool option, extraProjectInfo: obj option, optionsStamp: int64 option, userOpName) = reactor.EnqueueAndAwaitOpAsync (userOpName, "GetProjectOptionsFromScript", filename, fun ctok -> cancellable { use errors = new ErrorScope() // Do we add a reference to FSharp.Compiler.Interactive.Settings by default? let useFsiAuxLib = defaultArg useFsiAuxLib true - + let useSdkRefs = defaultArg useSdkRefs true let reduceMemoryUsage = ReduceMemoryFlag.Yes // Do we assume .NET Framework references for scripts? @@ -2847,7 +2847,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let loadClosure = LoadClosure.ComputeClosureOfScriptText(ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, sourceText, - CodeContext.Editing, useSimpleResolution, useFsiAuxLib, new Lexhelp.LexResourceManager(), + CodeContext.Editing, useSimpleResolution, useFsiAuxLib, useSdkRefs, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, tryGetMetadataSnapshot=tryGetMetadataSnapshot, reduceMemoryUsage=reduceMemoryUsage) @@ -3209,10 +3209,10 @@ type FSharpChecker(legacyReferenceResolver, projectCacheSize, keepAssemblyConten backgroundCompiler.KeepProjectAlive(options, userOpName) /// For a given script file, get the ProjectOptions implied by the #load closure - member ic.GetProjectOptionsFromScript(filename, sourceText, ?loadedTimeStamp, ?otherFlags, ?useFsiAuxLib, ?assumeDotNetFramework, ?extraProjectInfo: obj, ?optionsStamp: int64, ?userOpName: string) = + member ic.GetProjectOptionsFromScript(filename, source, ?loadedTimeStamp, ?otherFlags, ?useFsiAuxLib, ?useSdkRefs, ?assumeDotNetFramework, ?extraProjectInfo: obj, ?optionsStamp: int64, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" - backgroundCompiler.GetProjectOptionsFromScript(filename, sourceText, loadedTimeStamp, otherFlags, useFsiAuxLib, assumeDotNetFramework, extraProjectInfo, optionsStamp, userOpName) - + backgroundCompiler.GetProjectOptionsFromScript(filename, source, loadedTimeStamp, otherFlags, useFsiAuxLib, useSdkRefs, assumeDotNetFramework, extraProjectInfo, optionsStamp, userOpName) + member ic.GetProjectOptionsFromCommandLineArgs(projectFileName, argv, ?loadedTimeStamp, ?extraProjectInfo: obj) = let loadedTimeStamp = defaultArg loadedTimeStamp DateTime.MaxValue // Not 'now', we don't want to force reloading { ProjectFileName = projectFileName @@ -3323,7 +3323,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, reactorOps: IReactorOperatio let fsiCompilerOptions = CompileOptions.GetCoreFsiCompilerOptions tcConfigB CompileOptions.ParseCompilerOptions (ignore, fsiCompilerOptions, [ ]) - let loadClosure = LoadClosure.ComputeClosureOfScriptText(ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, sourceText, CodeContext.Editing, tcConfig.useSimpleResolution, tcConfig.useFsiAuxLib, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, tryGetMetadataSnapshot=(fun _ -> None), reduceMemoryUsage=reduceMemoryUsage) + let loadClosure = LoadClosure.ComputeClosureOfScriptText(ctok, legacyReferenceResolver, defaultFSharpBinariesDir, filename, sourceText, CodeContext.Editing, tcConfig.useSimpleResolution, tcConfig.useFsiAuxLib, tcConfig.useSdkRefs, new Lexhelp.LexResourceManager(), applyCompilerOptions, assumeDotNetFramework, tryGetMetadataSnapshot=(fun _ -> None), reduceMemoryUsage=reduceMemoryUsage) let! tcErrors, tcFileResult = Parser.CheckOneFile(parseResults, sourceText, filename, "project", tcConfig, tcGlobals, tcImports, tcState, Map.empty, Some loadClosure, backgroundDiagnostics, reactorOps, (fun () -> true), None, userOpName, suggestNamesForErrors) return diff --git a/src/fsharp/service/service.fsi b/src/fsharp/service/service.fsi index 4547068b515..a17abb46a3d 100755 --- a/src/fsharp/service/service.fsi +++ b/src/fsharp/service/service.fsi @@ -524,7 +524,7 @@ type public FSharpChecker = /// so that an 'unload' and 'reload' action will cause the script to be considered as a new project, /// so that references are re-resolved. /// An optional string used for tracing compiler operations associated with this request. - member GetProjectOptionsFromScript : filename: string * sourceText: ISourceText * ?loadedTimeStamp: DateTime * ?otherFlags: string[] * ?useFsiAuxLib: bool * ?assumeDotNetFramework: bool * ?extraProjectInfo: obj * ?optionsStamp: int64 * ?userOpName: string -> Async + member GetProjectOptionsFromScript : filename: string * sourceText: ISourceText * ?loadedTimeStamp: DateTime * ?otherFlags: string[] * ?useFsiAuxLib: bool * ?useSdkRefs: bool * ?assumeDotNetFramework: bool * ?extraProjectInfo: obj * ?optionsStamp: int64 * ?userOpName: string -> Async /// /// Get the FSharpProjectOptions implied by a set of command line arguments. diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index faca9cae453..2315ad7fee3 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -137,6 +137,11 @@ Zvažte použití parametru return! namísto return. + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. Zvažte použití parametru yield! namísto yield. diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 8bb6848ede1..239a4204745 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -137,6 +137,11 @@ Verwenden Sie ggf. "return!" anstelle von "return". + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. Verwenden Sie ggf. "yield!" anstelle von "yield". diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 87e9fb2e572..38474743bf3 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -137,6 +137,11 @@ Considere la posibilidad de usar "return!" en lugar de "return". + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. Considere la posibilidad de usar "yield!" en lugar de "yield". diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 839d65654bb..30dd74a4468 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -137,6 +137,11 @@ Utilisez 'return!' à la place de 'return'. + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. Utilisez 'yield!' à la place de 'yield'. diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index b0fe478b712..fbf6514bcd2 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -137,6 +137,11 @@ Provare a usare 'return!' invece di 'return'. + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. Provare a usare 'yield!' invece di 'yield'. diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 2d65a31b302..1a0b4c97ad9 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -137,6 +137,11 @@ 'return' の代わりに 'return!' を使うことを検討してください。 + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. 'yield' の代わりに 'yield!' を使うことを検討してください。 diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 1bb2aea5e39..b5df3ae2e62 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -137,6 +137,11 @@ 'return'이 아니라 'return!'를 사용하세요. + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. 'yield'가 아닌 'yield!'를 사용하세요. diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 17011e1f05d..5f46bf09e84 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -137,6 +137,11 @@ Rozważ użycie polecenia „return!” zamiast „return”. + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. Rozważ użycie polecenia „yield!” zamiast „yield”. diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index c76d1961070..dfd69dab7c1 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -137,6 +137,11 @@ Considere usar 'return!' em vez de 'return'. + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. Considere usar 'yield!' em vez de 'yield'. diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 49a5c382617..8b7fc126b59 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -137,6 +137,11 @@ Рекомендуется использовать "return!" вместо "return". + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. Рекомендуется использовать "yield!" вместо "yield". diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index f302bb7137b..f3aa876b53a 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -137,6 +137,11 @@ 'return' yerine 'return!' kullanmayı deneyin. + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. 'yield' yerine 'yield!' kullanmayı deneyin. diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 1626b50c116..33bef4332ee 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -137,6 +137,11 @@ 考虑使用 "return!",而非 "return"。 + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. 考虑使用 "yield!",而非 "yield"。 diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 9f0a87c0f32..c494db6287d 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -137,6 +137,11 @@ 請考慮使用 'return!',而不使用 'return'。 + + Use reference assemblies for DotNET framework references when available (Enabled by default)). + Use reference assemblies for DotNET framework references when available (Enabled by default)). + + Consider using 'yield!' instead of 'yield'. 請考慮使用 'yield!' 而不使用 'yield'。 diff --git a/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj b/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj index 7262d2fd895..b5b30d90671 100644 --- a/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj +++ b/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj @@ -17,6 +17,7 @@ + diff --git a/tests/FSharp.Compiler.UnitTests/VersionCompare.fs b/tests/FSharp.Compiler.UnitTests/VersionCompare.fs new file mode 100644 index 00000000000..f5d5f709b55 --- /dev/null +++ b/tests/FSharp.Compiler.UnitTests/VersionCompare.fs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. +namespace FSharp.Compiler.UnitTests + +open System +open System.Globalization +open System.Text +open NUnit.Framework +open FSharp.Compiler + +[] +module VersionCompare = + open FSharp.Compiler.DotNetFrameworkDependencies + + [] // 1.0.0 < 1.0.1 + [] // 1.0.0 = 1.0.0 + [] // 1.0.1 > 1.0.1 + [] // 0.0.9 < 1.0.0-Suffix1 + [] // 1.0.0 > 1.0.0-Suffix1 + [] // 1.0.0-Suffix1 < 1.0.0 + [] // 1.0.0-Suffix1 < 1.0.0-Suffix2 + [] // 1.0.0-Suffix2 > 1.0.0-Suffix1 + [] // 1.0.0-Suffix1 > 1.0.0-Suffix2 + [] // 1.0.1 > 1.0.0-Suffix1 + [] // 1.0.0-Suffix1 < 1.0.1 + let VersionCompareTest (str1: string, str2: string) : int = + versionCompare str1 str2 + + + [] + [] + let VersionCompareSortArrayHighestPreview _: string = + let versions = [| + "1.0.0-preview4-20000-01" + "3.0.0-preview4-27610-06" + "1.0.0-preview4-20000-02" + "3.0.0-preview4-27610-05" + "3.0.0-preview4-27609-10" + |] + versions |> Array.sortWith (versionCompare) |> Array.last + + [] + [] + let VersionCompareSortArrayHighestRelease _: string = + let versions = [| + "1.0.0-preview4-20000-01" + "3.0.0" + "3.0.0-preview4-27610-06" + "1.0.0-preview4-20000-02" + "3.0.0-preview4-27610-05" + "3.0.0-preview4-27609-10" + |] + versions |> Array.sortWith (versionCompare) |> Array.last + + [] + [] + let VersionCompareSortArrayEvenHighestRelease _: string = + let versions = [| + "3.0.1" + "1.0.0-preview4-20000-01" + "3.0.0" + "3.0.0-preview4-27610-06" + "1.0.0-preview4-20000-02" + "3.0.0-preview4-27610-05" + "3.0.0-preview4-27609-10" + |] + versions |> Array.sortWith (versionCompare) |> Array.last