From 5ea089349b45397ea588813f4d003bc067721cc2 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 12 Oct 2016 11:40:16 +0100 Subject: [PATCH 1/3] remove outputDirectory from compile-time search paths for scripts --- src/fsharp/CompileOps.fs | 6 ------ src/fsharp/MSBuildReferenceResolver.fs | 13 +++++-------- src/fsharp/ReferenceResolver.fs | 1 - 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index 84ba70bb3f7..835d677f7b5 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -3009,11 +3009,6 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = | Some(AMD64) -> "amd64" | Some(IA64) -> "ia64" - let outputDirectory = - match tcConfig.outputFile with - | Some(outputFile) -> tcConfig.MakePathAbsolute outputFile - | None -> tcConfig.implicitIncludeDir - let targetFrameworkDirectories = tcConfig.ClrRoot // First, try to resolve everything as a file using simple resolution @@ -3034,7 +3029,6 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, - Path.GetDirectoryName(outputDirectory), tcConfig.fsharpBinariesDir, // FSharp binaries directory tcConfig.includes, // Explicit include directories tcConfig.implicitIncludeDir, // Implicit include directory (likely the project directory) diff --git a/src/fsharp/MSBuildReferenceResolver.fs b/src/fsharp/MSBuildReferenceResolver.fs index f8fc2e2b0e0..05bce192b7d 100644 --- a/src/fsharp/MSBuildReferenceResolver.fs +++ b/src/fsharp/MSBuildReferenceResolver.fs @@ -208,7 +208,6 @@ module internal MSBuildReferenceResolver = targetFrameworkVersion: string, targetFrameworkDirectories: string list, targetProcessorArchitecture: string, - outputDirectory: string, fsharpCoreDir: string, explicitIncludeDirs: string list, implicitIncludeDir: string, @@ -289,7 +288,6 @@ module internal MSBuildReferenceResolver = yield implicitIncludeDir // Usually the project directory yield registry yield "{AssemblyFolders}" - yield outputDirectory yield "{GAC}" // use path to implementation assemblies as the last resort yield! GetPathToDotNetFrameworkImlpementationAssemblies targetFrameworkVersion @@ -356,7 +354,6 @@ module internal MSBuildReferenceResolver = [implicitIncludeDir] @ // Usually the project directory [sprintf "{Registry:%s,%s,%s%s}" frameworkRegistryBase targetFrameworkVersion assemblyFoldersSuffix assemblyFoldersConditions] @ // Like {Registry:Software\Microsoft\.NETFramework,v2.0,AssemblyFoldersEx} ["{AssemblyFolders}"] @ - [outputDirectory] @ ["{GAC}"] @ // use path to implementation assemblies as the last resort GetPathToDotNetFrameworkImlpementationAssemblies targetFrameworkVersion @@ -383,7 +380,7 @@ module internal MSBuildReferenceResolver = /// Perform the resolution on rooted and unrooted paths, and then combine the results. let Resolve(resolutionEnvironment, references, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, - outputDirectory, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) = + fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) = // The {RawFileName} target is 'dangerous', in the sense that is uses Directory.GetCurrentDirectory() to resolve unrooted file paths. // It is unreliable to use this mutable global state inside Visual Studio. As a result, we partition all references into a "rooted" set @@ -405,9 +402,9 @@ module internal MSBuildReferenceResolver = let rooted, unrooted = references |> Array.partition (fst >> FileSystem.IsPathRootedShim) - let rootedResults = ResolveCore(resolutionEnvironment, rooted, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, outputDirectory, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, true, logMessage, logWarning, logError) + let rootedResults = ResolveCore(resolutionEnvironment, rooted, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, true, logMessage, logWarning, logError) - let unrootedResults = ResolveCore(resolutionEnvironment, unrooted, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, outputDirectory, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, false, logMessage, logWarning, logError) + let unrootedResults = ResolveCore(resolutionEnvironment, unrooted, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, false, logMessage, logWarning, logError) // now unify the two sets of results Array.concat [| rootedResults; unrootedResults |] @@ -417,8 +414,8 @@ module internal MSBuildReferenceResolver = member __.HighestInstalledNetFrameworkVersion() = HighestInstalledNetFrameworkVersion() member __.DotNetFrameworkReferenceAssembliesRootDirectory = DotNetFrameworkReferenceAssembliesRootDirectory member __.Resolve(resolutionEnvironment, references, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, - outputDirectory, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) = + fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) = Resolve(resolutionEnvironment, references, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, - outputDirectory, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) + fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) } diff --git a/src/fsharp/ReferenceResolver.fs b/src/fsharp/ReferenceResolver.fs index d9e48bcd69d..df230aa1175 100644 --- a/src/fsharp/ReferenceResolver.fs +++ b/src/fsharp/ReferenceResolver.fs @@ -48,7 +48,6 @@ module internal ReferenceResolver = targetFrameworkVersion:string * targetFrameworkDirectories:string list * targetProcessorArchitecture:string * - outputDirectory: string * fsharpCoreDir:string * explicitIncludeDirs:string list * implicitIncludeDir:string * From 50d106f67c3a8d1a05af0d18fc60f595347e58f4 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 12 Oct 2016 11:49:49 +0100 Subject: [PATCH 2/3] remove code duplication --- src/fsharp/MSBuildReferenceResolver.fs | 42 -------------------------- 1 file changed, 42 deletions(-) diff --git a/src/fsharp/MSBuildReferenceResolver.fs b/src/fsharp/MSBuildReferenceResolver.fs index 05bce192b7d..3e932a74e4f 100644 --- a/src/fsharp/MSBuildReferenceResolver.fs +++ b/src/fsharp/MSBuildReferenceResolver.fs @@ -319,48 +319,6 @@ module internal MSBuildReferenceResolver = rar.TargetProcessorArchitecture <- targetProcessorArchitecture rar.CopyLocalDependenciesWhenParentReferenceInGac <- true #endif - rar.Assemblies <- -#if RESHAPED_MSBUILD - [||] -#else - [| for (referenceName,baggage) in references -> - let item = new Microsoft.Build.Utilities.TaskItem(referenceName) :> ITaskItem - item.SetMetadata("Baggage", baggage) - item - |] -#endif - let rawFileNamePath = if allowRawFileName then ["{RawFileName}"] else [] - let searchPaths = - match resolutionEnvironment with - | DesignTimeLike - | RuntimeLike -> - logMessage("Using scripting resolution precedence.") - // These are search paths for runtime-like or scripting resolution. GAC searching is present. - rawFileNamePath @ // Quick-resolve straight to filename first - explicitIncludeDirs @ // From -I, #I - [fsharpCoreDir] @ // Location of explicit reference to FSharp.Core, otherwise location of fsc.exe - [implicitIncludeDir] @ // Usually the project directory - ["{TargetFrameworkDirectory}"] @ - [sprintf "{Registry:%s,%s,%s%s}" frameworkRegistryBase targetFrameworkVersion assemblyFoldersSuffix assemblyFoldersConditions] @ - ["{AssemblyFolders}"] @ - ["{GAC}"] - | CompileTimeLike -> - logMessage("Using compilation resolution precedence.") - // These are search paths for compile-like resolution. GAC searching is not present. - ["{TargetFrameworkDirectory}"] @ - rawFileNamePath @ // Quick-resolve straight to filename first - explicitIncludeDirs @ // From -I, #I - [fsharpCoreDir] @ // Location of explicit reference to FSharp.Core, otherwise location of fsc.exe - [implicitIncludeDir] @ // Usually the project directory - [sprintf "{Registry:%s,%s,%s%s}" frameworkRegistryBase targetFrameworkVersion assemblyFoldersSuffix assemblyFoldersConditions] @ // Like {Registry:Software\Microsoft\.NETFramework,v2.0,AssemblyFoldersEx} - ["{AssemblyFolders}"] @ - ["{GAC}"] @ - // use path to implementation assemblies as the last resort - GetPathToDotNetFrameworkImlpementationAssemblies targetFrameworkVersion - - rar.SearchPaths <- searchPaths |> Array.ofList - - rar.AllowedAssemblyExtensions <- [| ".dll" ; ".exe" |] let succeeded = rar.Execute() From b1d9faaf863572709f255f3882b43b9d9d7a7237 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 12 Oct 2016 12:23:27 +0100 Subject: [PATCH 3/3] code cleanup --- src/fsharp/CompileOps.fs | 152 ++++++++++----------- src/fsharp/CompileOps.fsi | 4 +- src/fsharp/MSBuildReferenceResolver.fs | 177 ++++++++++++------------- src/fsharp/ReferenceResolver.fs | 5 +- src/fsharp/vs/IncrementalBuild.fs | 5 +- src/fsharp/vs/service.fs | 2 +- 6 files changed, 163 insertions(+), 182 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index 835d677f7b5..94516030c82 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -2787,7 +2787,7 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = (sourceFiles |> List.mapi (fun i _ -> (i = n-1)), tcConfig.target.IsExe) // This call can fail if no CLR is found (this is the path to mscorlib) - member tcConfig.ClrRoot = + member tcConfig.TargetFrameworkDirectories = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind (BuildPhase.Parameter) match tcConfig.clrRoot with | Some x -> @@ -2844,7 +2844,7 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = member tcConfig.IsSystemAssembly (filename:string) = try FileSystem.SafeExists filename && - ((tcConfig.ClrRoot |> List.exists (fun clrRoot -> clrRoot = Path.GetDirectoryName filename)) || + ((tcConfig.TargetFrameworkDirectories |> List.exists (fun clrRoot -> clrRoot = Path.GetDirectoryName filename)) || (systemAssemblies |> List.exists (fun sysFile -> sysFile = fileNameWithoutExtension filename))) with _ -> false @@ -2852,7 +2852,7 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = // This is not the complete set of search paths, it is just the set // that is special to F# (as compared to MSBuild resolution) member tcConfig.SearchPathsForLibraryFiles = - [ yield! tcConfig.ClrRoot + [ yield! tcConfig.TargetFrameworkDirectories yield! List.map (tcConfig.MakePathAbsolute) tcConfig.includes yield tcConfig.implicitIncludeDir yield tcConfig.fsharpBinariesDir ] @@ -2977,13 +2977,16 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = assemblyName, highestPosition, assemblyGroup) |> Array.ofSeq - let logmessage showMessages = + let logMessage showMessages = if showMessages && tcConfig.showReferenceResolutions then (fun (message:string)->dprintf "%s\n" message) else ignore - let logwarning showMessages = - (fun code message-> + let logErrorOrWarning showMessages = + (fun isError code message-> if showMessages && mode = ReportErrors then + if isError then + errorR(MSBuildReferenceResolutionError(code,message,errorAndWarningRange)) + else match code with // These are warnings that mean 'not resolved' for some assembly. // Note that we don't get to know the name of the assembly that couldn't be resolved. @@ -2992,15 +2995,10 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = | "MSB3106" -> () | _ -> - (if code = "MSB3245" then errorR else warning) - (MSBuildReferenceResolutionWarning(code,message,errorAndWarningRange))) - - let logerror showMessages = - (fun code message -> - if showMessages && mode = ReportErrors then - errorR(MSBuildReferenceResolutionError(code,message,errorAndWarningRange))) - - let targetFrameworkVersion = tcConfig.targetFrameworkVersion + if code = "MSB3245" then + errorR(MSBuildReferenceResolutionWarning(code,message,errorAndWarningRange)) + else + warning(MSBuildReferenceResolutionWarning(code,message,errorAndWarningRange))) let targetProcessorArchitecture = match tcConfig.platform with @@ -3009,8 +3007,6 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = | Some(AMD64) -> "amd64" | Some(IA64) -> "ia64" - let targetFrameworkDirectories = tcConfig.ClrRoot - // First, try to resolve everything as a file using simple resolution let resolvedAsFile = groupedReferences @@ -3026,13 +3022,13 @@ type TcConfig private (data : TcConfigBuilder,validate:bool) = tcConfig.referenceResolver.Resolve (tcConfig.resolutionEnvironment, references, - targetFrameworkVersion, - targetFrameworkDirectories, + tcConfig.targetFrameworkVersion, + tcConfig.TargetFrameworkDirectories, targetProcessorArchitecture, tcConfig.fsharpBinariesDir, // FSharp binaries directory tcConfig.includes, // Explicit include directories tcConfig.implicitIncludeDir, // Implicit include directory (likely the project directory) - logmessage showMessages, logwarning showMessages, logerror showMessages) + logMessage showMessages, logErrorOrWarning showMessages) with ReferenceResolver.ResolutionFailure -> error(Error(FSComp.SR.buildAssemblyResolutionFailed(),errorAndWarningRange)) @@ -4235,38 +4231,25 @@ type TcImports(tcConfigP:TcConfigProvider, initialResolutions:TcAssemblyResoluti let invalidateCcu = new Event<_>() #endif - // Adjust where the code for known F# libraries live relative to the installation of F# - let codeDir = - let dir = minfo.compileTimeWorkingDir - let knownLibraryLocation = @"src\fsharp\" // Help highlighting... " - let knownLibarySuffixes = - [ @"FSharp.Core" - @"FSharp.PowerPack" - @"FSharp.PowerPack.Linq" - @"FSharp.PowerPack.Metadata" ] - match knownLibarySuffixes |> List.tryFind (fun x -> dir.EndsWith(knownLibraryLocation + x,StringComparison.OrdinalIgnoreCase)) with - | None -> - dir - | Some libSuffix -> - // add "..\lib\FSharp.Core" to the F# binaries directory - Path.Combine(Path.Combine(tcConfig.fsharpBinariesDir,@"..\lib"),libSuffix) - - let ccu = - CcuThunk.Create(ccuName, { ILScopeRef=ilScopeRef - Stamp = newStamp() - FileName = Some filename - QualifiedName= Some(ilScopeRef.QualifiedName) - SourceCodeDirectory = codeDir (* note: in some cases we fix up this information later *) - IsFSharp=true - Contents = mspec + let codeDir = minfo.compileTimeWorkingDir + let ccuData : CcuData = + { ILScopeRef=ilScopeRef + Stamp = newStamp() + FileName = Some filename + QualifiedName= Some(ilScopeRef.QualifiedName) + SourceCodeDirectory = codeDir (* note: in some cases we fix up this information later *) + IsFSharp=true + Contents = mspec #if EXTENSIONTYPING - InvalidateEvent=invalidateCcu.Publish - IsProviderGenerated = false - ImportProvidedType = (fun ty -> Import.ImportProvidedType (tcImports.GetImportMap()) m ty) + InvalidateEvent=invalidateCcu.Publish + IsProviderGenerated = false + ImportProvidedType = (fun ty -> Import.ImportProvidedType (tcImports.GetImportMap()) m ty) #endif - UsesFSharp20PlusQuotations = minfo.usesQuotations - MemberSignatureEquality= (fun ty1 ty2 -> Tastops.typeEquivAux EraseAll (tcImports.GetTcGlobals()) ty1 ty2) - TypeForwarders = ImportILAssemblyTypeForwarders(tcImports.GetImportMap,m, ilModule.GetRawTypeForwarders()) }) + UsesFSharp20PlusQuotations = minfo.usesQuotations + MemberSignatureEquality= (fun ty1 ty2 -> Tastops.typeEquivAux EraseAll (tcImports.GetTcGlobals()) ty1 ty2) + TypeForwarders = ImportILAssemblyTypeForwarders(tcImports.GetImportMap,m, ilModule.GetRawTypeForwarders()) } + + let ccu = CcuThunk.Create(ccuName, ccuData) let optdata = lazy @@ -4281,15 +4264,15 @@ type TcImports(tcConfigP:TcConfigProvider, initialResolutions:TcAssemblyResoluti Some res) let ilg = defaultArg ilGlobalsOpt EcmaILGlobals let ccuinfo = - { FSharpViewOfMetadata=ccu - AssemblyAutoOpenAttributes = ilModule.GetAutoOpenAttributes(ilg) - AssemblyInternalsVisibleToAttributes = ilModule.GetInternalsVisibleToAttributes(ilg) - FSharpOptimizationData=optdata + { FSharpViewOfMetadata=ccu + AssemblyAutoOpenAttributes = ilModule.GetAutoOpenAttributes(ilg) + AssemblyInternalsVisibleToAttributes = ilModule.GetInternalsVisibleToAttributes(ilg) + FSharpOptimizationData=optdata #if EXTENSIONTYPING - IsProviderGenerated = false - TypeProviders = [] + IsProviderGenerated = false + TypeProviders = [] #endif - ILScopeRef = ilScopeRef } + ILScopeRef = ilScopeRef } let phase2() = #if EXTENSIONTYPING match ilModule.TryGetRawILModule() with @@ -4338,15 +4321,16 @@ type TcImports(tcConfigP:TcConfigProvider, initialResolutions:TcAssemblyResoluti let phase2() = [tcImports.FindCcuInfo(m,ilShortAssemName,lookupOnly=true)] dllinfo,phase2 else - let dllinfo = {RawMetadata=assemblyData - FileName=filename + let dllinfo = + { RawMetadata=assemblyData + FileName=filename #if EXTENSIONTYPING - ProviderGeneratedAssembly=None - IsProviderGenerated=false - ProviderGeneratedStaticLinkMap = None + ProviderGeneratedAssembly=None + IsProviderGenerated=false + ProviderGeneratedStaticLinkMap = None #endif - ILScopeRef = ilScopeRef - ILAssemblyRefs = assemblyData.ILAssemblyRefs } + ILScopeRef = ilScopeRef + ILAssemblyRefs = assemblyData.ILAssemblyRefs } tcImports.RegisterDll(dllinfo) let ilg = defaultArg ilGlobalsOpt EcmaILGlobals let phase2 = @@ -5148,26 +5132,31 @@ type TcState = tcsTcImplEnv = tcEnvAtEndOfLastInput } +/// Create the initial type checking state for compiling an assembly let GetInitialTcState(m,ccuName,tcConfig:TcConfig,tcGlobals,tcImports:TcImports,niceNameGen,tcEnv0) = ignore tcImports + // Create a ccu to hold all the results of compilation let ccuType = NewCcuContents ILScopeRef.Local m ccuName (NewEmptyModuleOrNamespaceType Namespace) - let ccu = - CcuThunk.Create(ccuName,{IsFSharp=true - UsesFSharp20PlusQuotations=false + + let ccuData : CcuData = + { IsFSharp=true + UsesFSharp20PlusQuotations=false #if EXTENSIONTYPING - InvalidateEvent=(new Event<_>()).Publish - IsProviderGenerated = false - ImportProvidedType = (fun ty -> Import.ImportProvidedType (tcImports.GetImportMap()) m ty) + InvalidateEvent=(new Event<_>()).Publish + IsProviderGenerated = false + ImportProvidedType = (fun ty -> Import.ImportProvidedType (tcImports.GetImportMap()) m ty) #endif - FileName=None - Stamp = newStamp() - QualifiedName= None - SourceCodeDirectory = tcConfig.implicitIncludeDir - ILScopeRef=ILScopeRef.Local - Contents=ccuType - MemberSignatureEquality= (Tastops.typeEquivAux EraseAll tcGlobals) - TypeForwarders=Map.empty }) + FileName=None + Stamp = newStamp() + QualifiedName= None + SourceCodeDirectory = tcConfig.implicitIncludeDir + ILScopeRef=ILScopeRef.Local + Contents=ccuType + MemberSignatureEquality= (Tastops.typeEquivAux EraseAll tcGlobals) + TypeForwarders=Map.empty } + + let ccu = CcuThunk.Create(ccuName,ccuData) // OK, is this is the FSharp.Core CCU then fix it up. if tcConfig.compilingFslib then @@ -5185,7 +5174,7 @@ let GetInitialTcState(m,ccuName,tcConfig:TcConfig,tcGlobals,tcImports:TcImports, tcsRootSigsAndImpls = RootSigsAndImpls (rootSigs, rootImpls, allSigModulTyp, allImplementedSigModulTyp) } -/// Typecheck a single file or interactive entry into F# Interactive +/// Typecheck a single file (or interactive entry into F# Interactive) let TypeCheckOneInputEventually (checkForErrors , tcConfig:TcConfig, tcImports:TcImports, tcGlobals, prefixPathOpt, tcSink, tcState: TcState, inp: ParsedInput) = @@ -5296,12 +5285,14 @@ let TypeCheckOneInputEventually return (tcState.TcEnvFromSignatures,EmptyTopAttrs,[]),tcState } +/// Typecheck a single file (or interactive entry into F# Interactive) let TypeCheckOneInput (checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt) tcState inp = // 'use' ensures that the warning handler is restored at the end use unwindEL = PushErrorLoggerPhaseUntilUnwind(fun oldLogger -> GetErrorLoggerFilteringByScopedPragmas(false,GetScopedPragmasForInput(inp),oldLogger) ) use unwindBP = PushThreadBuildPhaseUntilUnwind (BuildPhase.TypeCheck) TypeCheckOneInputEventually (checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, TcResultsSink.NoSink, tcState, inp) |> Eventually.force +/// Finish checking multiple files (or one interactive entry into F# Interactive) let TypeCheckMultipleInputsFinish(results,tcState: TcState) = let tcEnvsAtEndFile,topAttrs,mimpls = List.unzip3 results @@ -5312,11 +5303,12 @@ let TypeCheckMultipleInputsFinish(results,tcState: TcState) = (tcEnvAtEndOfLastFile,topAttrs,mimpls),tcState +/// Check multiple files (or one interactive entry into F# Interactive) let TypeCheckMultipleInputs (checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, inputs) = let results,tcState = (tcState, inputs) ||> List.mapFold (TypeCheckOneInput (checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt)) TypeCheckMultipleInputsFinish(results,tcState) -let TypeCheckSingleInputAndFinishEventually(checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) = +let TypeCheckOneInputAndFinishEventually(checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) = eventually { let! results,tcState = TypeCheckOneInputEventually(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) return TypeCheckMultipleInputsFinish([results],tcState) diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi index cc3f9d415c2..62437bafa57 100755 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -502,7 +502,7 @@ type TcConfig = member ComputeLightSyntaxInitialStatus : string -> bool - member ClrRoot : string list + member TargetFrameworkDirectories : string list /// Get the loaded sources that exist and issue a warning for the ones that don't member GetAvailableLoadedSources : unit -> (range*string) list @@ -724,7 +724,7 @@ val TypeCheckClosedInputSetFinish : TypedImplFile list * TcState -> TcState * Ty val TypeCheckClosedInputSet :(unit -> bool) * TcConfig * TcImports * TcGlobals * Ast.LongIdent option * TcState * Ast.ParsedInput list -> TcState * TopAttribs * TypedImplFile list * TcEnv /// Check a single input and finish the checking -val TypeCheckSingleInputAndFinishEventually : +val TypeCheckOneInputAndFinishEventually : (unit -> bool) * TcConfig * TcImports * TcGlobals * Ast.LongIdent option * NameResolution.TcResultsSink * TcState * Ast.ParsedInput -> Eventually<(TcEnv * TopAttribs * TypedImplFile list) * TcState> diff --git a/src/fsharp/MSBuildReferenceResolver.fs b/src/fsharp/MSBuildReferenceResolver.fs index 3e932a74e4f..c645b8b1af9 100644 --- a/src/fsharp/MSBuildReferenceResolver.fs +++ b/src/fsharp/MSBuildReferenceResolver.fs @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.FSharp.Compiler +module internal Microsoft.FSharp.Compiler.MSBuildReferenceResolver -module internal MSBuildReferenceResolver = + open System + open System.IO #if FX_RESHAPED_REFLECTION open Microsoft.FSharp.Core.ReflectionAdapters @@ -14,11 +15,9 @@ module internal MSBuildReferenceResolver = open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library open Microsoft.FSharp.Compiler.ReferenceResolver - open System open Microsoft.Build.Tasks open Microsoft.Build.Utilities open Microsoft.Build.Framework - open System.IO /// Get the Reference Assemblies directory for the .NET Framework on Window. let DotNetFrameworkReferenceAssembliesRootDirectory = @@ -169,38 +168,41 @@ module internal MSBuildReferenceResolver = let TooltipForResolvedFrom(resolvedFrom, fusionName, redist) = fun (originalReference,resolvedPath) -> let originalReferenceName = originalReference + let resolvedPath = // Don't show the resolved path if it is identical to what was referenced. if originalReferenceName = resolvedPath then String.Empty else resolvedPath - let lineIfExists(append) = - if not(String.IsNullOrEmpty(append)) then append.Trim([|' '|])+"\n" - else "" + + let lineIfExists text = + if String.IsNullOrEmpty text then "" + else text.Trim(' ')+"\n" + match resolvedFrom with | AssemblyFolders -> - lineIfExists(resolvedPath) - + lineIfExists(fusionName) - + (FSComp.SR.assemblyResolutionFoundByAssemblyFoldersKey()) + lineIfExists resolvedPath + + lineIfExists fusionName + + FSComp.SR.assemblyResolutionFoundByAssemblyFoldersKey() | AssemblyFoldersEx -> - lineIfExists(resolvedPath) - + lineIfExists(fusionName) - + (FSComp.SR.assemblyResolutionFoundByAssemblyFoldersExKey()) + lineIfExists resolvedPath + + lineIfExists fusionName + + FSComp.SR.assemblyResolutionFoundByAssemblyFoldersExKey() | TargetFrameworkDirectory -> - lineIfExists(resolvedPath) - + lineIfExists(fusionName) - + (FSComp.SR.assemblyResolutionNetFramework()) + lineIfExists resolvedPath + + lineIfExists fusionName + + FSComp.SR.assemblyResolutionNetFramework() | Unknown -> // Unknown when resolved by plain directory search without help from MSBuild resolver. - lineIfExists(resolvedPath) - + lineIfExists(fusionName) + lineIfExists resolvedPath + + lineIfExists fusionName | RawFileName -> - lineIfExists(fusionName) + lineIfExists fusionName | GlobalAssemblyCache -> - lineIfExists(fusionName) - + (FSComp.SR.assemblyResolutionGAC())+ "\n" - + lineIfExists(redist) + lineIfExists fusionName + + lineIfExists (FSComp.SR.assemblyResolutionGAC()) + + lineIfExists redist | Path _ -> - lineIfExists(resolvedPath) - + lineIfExists(fusionName) + lineIfExists resolvedPath + + lineIfExists fusionName /// Perform assembly resolution by instantiating the ResolveAssemblyReference task directly from the MSBuild SDK. let ResolveCore(resolutionEnvironment: ResolutionEnvironment, @@ -213,8 +215,7 @@ module internal MSBuildReferenceResolver = implicitIncludeDir: string, allowRawFileName: bool, logMessage: (string -> unit), - logWarning: (string -> string -> unit), - logError: (string -> string -> unit)) = + logErrorOrWarning: (bool -> string -> string -> unit)) = let frameworkRegistryBase, assemblyFoldersSuffix, assemblyFoldersConditions = "Software\Microsoft\.NetFramework", "AssemblyFoldersEx" , "" @@ -232,14 +233,14 @@ module internal MSBuildReferenceResolver = member __.BuildProjectFile(projectFileName, targetNames, globalProperties, targetOutputs) = true #if RESHAPED_MSBUILD member __.LogCustomEvent(e) = protect (fun () -> logMessage ((e.GetPropertyValue("Message")) :?> string)) - member __.LogErrorEvent(e) = protect (fun () -> logError ((e.GetPropertyValue("Code")) :?> string) ((e.GetPropertyValue("Message")) :?> string)) + member __.LogErrorEvent(e) = protect (fun () -> logErrorOrWarning true ((e.GetPropertyValue("Code")) :?> string) ((e.GetPropertyValue("Message")) :?> string)) member __.LogMessageEvent(e) = protect (fun () -> logMessage ((e.GetPropertyValue("Message")) :?> string)) - member __.LogWarningEvent(e) = protect (fun () -> logWarning ((e.GetPropertyValue("Code")) :?> string) ((e.GetPropertyValue("Message")) :?> string)) + member __.LogWarningEvent(e) = protect (fun () -> logErrorOrWarning false ((e.GetPropertyValue("Code")) :?> string) ((e.GetPropertyValue("Message")) :?> string)) #else member __.LogCustomEvent(e) = protect (fun () -> logMessage e.Message) - member __.LogErrorEvent(e) = protect (fun () -> logError e.Code e.Message) + member __.LogErrorEvent(e) = protect (fun () -> logErrorOrWarning true e.Code e.Message) member __.LogMessageEvent(e) = protect (fun () -> logMessage e.Message) - member __.LogWarningEvent(e) = protect (fun () -> logWarning e.Code e.Message) + member __.LogWarningEvent(e) = protect (fun () -> logErrorOrWarning false e.Code e.Message) #endif member __.ColumnNumberOfTaskNode with get() = 1 member __.LineNumberOfTaskNode with get() = 1 @@ -260,37 +261,30 @@ module internal MSBuildReferenceResolver = let explicitIncludeDirs = explicitIncludeDirs |> List.filter(String.IsNullOrEmpty >> not) - let rawFileNamePath = if allowRawFileName then ["{RawFileName}"] else [] - let registry = sprintf "{Registry:%s,%s,%s%s}" frameworkRegistryBase targetFrameworkVersion assemblyFoldersSuffix assemblyFoldersConditions - [| match resolutionEnvironment with - | DesignTimeLike - | RuntimeLike -> - logMessage("Using scripting resolution precedence.") - // These are search paths for runtime-like or scripting resolution. GAC searching is present. - yield! rawFileNamePath // Quick-resolve straight to filename first - yield! explicitIncludeDirs // From -I, #I - yield fsharpCoreDir // Location of explicit reference to FSharp.Core, otherwise location of fsc.exe - yield implicitIncludeDir // Usually the project directory - yield "{TargetFrameworkDirectory}" - yield registry - yield "{AssemblyFolders}" - yield "{GAC}" - - | CompileTimeLike -> - logMessage("Using compilation resolution precedence.") - // These are search paths for compile-like resolution. GAC searching is not present. - yield "{TargetFrameworkDirectory}" - yield! rawFileNamePath // Quick-resolve straight to filename first - yield! explicitIncludeDirs // From -I, #I - yield fsharpCoreDir // Location of explicit reference to FSharp.Core, otherwise location of fsc.exe - yield implicitIncludeDir // Usually the project directory - yield registry - yield "{AssemblyFolders}" - yield "{GAC}" - // use path to implementation assemblies as the last resort - yield! GetPathToDotNetFrameworkImlpementationAssemblies targetFrameworkVersion + [| // When compiling scripts, for some reason we have always historically put TargetFrameworkDirectory first + // It is unclear why. + match resolutionEnvironment with + | CompileTimeLike -> yield "{TargetFrameworkDirectory}" + | DesignTimeLike | RuntimeLike -> () + + // Quick-resolve straight to filename first + if allowRawFileName then + yield "{RawFileName}" + yield! explicitIncludeDirs // From -I, #I + yield fsharpCoreDir // Location of explicit reference to FSharp.Core, otherwise location of fsc.exe + yield implicitIncludeDir // Usually the project directory + + match resolutionEnvironment with + | DesignTimeLike | RuntimeLike -> yield "{TargetFrameworkDirectory}" + | CompileTimeLike -> () + + yield registry + yield "{AssemblyFolders}" + yield "{GAC}" + // use path to implementation assemblies as the last resort + yield! GetPathToDotNetFrameworkImlpementationAssemblies targetFrameworkVersion |] let assemblies = @@ -336,44 +330,39 @@ module internal MSBuildReferenceResolver = resolvedFiles - /// Perform the resolution on rooted and unrooted paths, and then combine the results. - let Resolve(resolutionEnvironment, references, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, - fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) = - - // The {RawFileName} target is 'dangerous', in the sense that is uses Directory.GetCurrentDirectory() to resolve unrooted file paths. - // It is unreliable to use this mutable global state inside Visual Studio. As a result, we partition all references into a "rooted" set - // (which contains e.g. C:\MyDir\MyAssem.dll) and "unrooted" (everything else). We only allow "rooted" to use {RawFileName}. Note that - // unrooted may still find 'local' assemblies by virtue of the fact that "implicitIncludeDir" is one of the places searched during - // assembly resolution. - let references = - [| for ((file,baggage) as data) in references -> - // However, MSBuild will not resolve 'relative' paths, even when e.g. implicitIncludeDir is part of the search. As a result, - // if we have an unrooted path+filename, we'll assume this is relative to the project directory and root it. - if FileSystem.IsPathRootedShim(file) then - data // fine, e.g. "C:\Dir\foo.dll" - elif not(file.Contains("\\") || file.Contains("/")) then - data // fine, e.g. "System.Transactions.dll" - else - // we have a 'relative path', e.g. "bin/Debug/foo.exe" or "..\Yadda\bar.dll" - // turn it into an absolute path based at implicitIncludeDir - (Path.Combine(implicitIncludeDir, file), baggage) |] - - let rooted, unrooted = references |> Array.partition (fst >> FileSystem.IsPathRootedShim) - - let rootedResults = ResolveCore(resolutionEnvironment, rooted, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, true, logMessage, logWarning, logError) - - let unrootedResults = ResolveCore(resolutionEnvironment, unrooted, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, false, logMessage, logWarning, logError) - - // now unify the two sets of results - Array.concat [| rootedResults; unrootedResults |] - let Resolver = { new ReferenceResolver.Resolver with member __.HighestInstalledNetFrameworkVersion() = HighestInstalledNetFrameworkVersion() member __.DotNetFrameworkReferenceAssembliesRootDirectory = DotNetFrameworkReferenceAssembliesRootDirectory - member __.Resolve(resolutionEnvironment, references, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, - fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) = - Resolve(resolutionEnvironment, references, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, - fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logWarning, logError) + /// Perform the resolution on rooted and unrooted paths, and then combine the results. + member __.Resolve(resolutionEnvironment, references, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, + fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, logMessage, logErrorOrWarning) = + + // The {RawFileName} target is 'dangerous', in the sense that is uses Directory.GetCurrentDirectory() to resolve unrooted file paths. + // It is unreliable to use this mutable global state inside Visual Studio. As a result, we partition all references into a "rooted" set + // (which contains e.g. C:\MyDir\MyAssem.dll) and "unrooted" (everything else). We only allow "rooted" to use {RawFileName}. Note that + // unrooted may still find 'local' assemblies by virtue of the fact that "implicitIncludeDir" is one of the places searched during + // assembly resolution. + let references = + [| for ((file,baggage) as data) in references -> + // However, MSBuild will not resolve 'relative' paths, even when e.g. implicitIncludeDir is part of the search. As a result, + // if we have an unrooted path+filename, we'll assume this is relative to the project directory and root it. + if FileSystem.IsPathRootedShim(file) then + data // fine, e.g. "C:\Dir\foo.dll" + elif not(file.Contains("\\") || file.Contains("/")) then + data // fine, e.g. "System.Transactions.dll" + else + // We have a 'relative path', e.g. "bin/Debug/foo.exe" or "..\Yadda\bar.dll" + // turn it into an absolute path based at implicitIncludeDir + (Path.Combine(implicitIncludeDir, file), baggage) |] + + let rooted, unrooted = references |> Array.partition (fst >> FileSystem.IsPathRootedShim) + + let rootedResults = ResolveCore(resolutionEnvironment, rooted, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, true, logMessage, logErrorOrWarning) + + let unrootedResults = ResolveCore(resolutionEnvironment, unrooted, targetFrameworkVersion, targetFrameworkDirectories, targetProcessorArchitecture, fsharpCoreDir, explicitIncludeDirs, implicitIncludeDir, false, logMessage, logErrorOrWarning) + + // now unify the two sets of results + Array.concat [| rootedResults; unrootedResults |] } diff --git a/src/fsharp/ReferenceResolver.fs b/src/fsharp/ReferenceResolver.fs index df230aa1175..8228ac8da96 100644 --- a/src/fsharp/ReferenceResolver.fs +++ b/src/fsharp/ReferenceResolver.fs @@ -51,7 +51,6 @@ module internal ReferenceResolver = fsharpCoreDir:string * explicitIncludeDirs:string list * implicitIncludeDir:string * - logmessage:(string->unit) * - logwarning:(string->string->unit) * - logerror:(string->string->unit) + logMessage:(string->unit) * + logErrorOrWarning:(bool -> string -> string -> unit) -> ResolvedFile[] diff --git a/src/fsharp/vs/IncrementalBuild.fs b/src/fsharp/vs/IncrementalBuild.fs index 774c1aeecd7..fc1eb6c2b31 100755 --- a/src/fsharp/vs/IncrementalBuild.fs +++ b/src/fsharp/vs/IncrementalBuild.fs @@ -1081,7 +1081,7 @@ type TypeCheckAccumulator = /// Global service state -type FrameworkImportsCacheKey = (*resolvedpath*)string list * string * (*ClrRoot*)string list* (*fsharpBinaries*)string +type FrameworkImportsCacheKey = (*resolvedpath*)string list * string * (*TargetFrameworkDirectories*)string list* (*fsharpBinaries*)string type FrameworkImportsCache(keepStrongly) = let frameworkTcImportsCache = AgedLookup(keepStrongly, areSame=(fun (x,y) -> x = y)) @@ -1096,6 +1096,7 @@ type FrameworkImportsCache(keepStrongly) = frameworkDLLs |> List.map (fun ar->ar.resolvedPath) // The cache key. Just the minimal data. |> List.sort // Sort to promote cache hits. + let tcGlobals,frameworkTcImports = // Prepare the frameworkTcImportsCache // @@ -1104,7 +1105,7 @@ type FrameworkImportsCache(keepStrongly) = // FSharp.Core.dll and mscorlib.dll) must be logically invariant of all the other compiler configuration parameters. let key = (frameworkDLLsKey, tcConfig.primaryAssembly.Name, - tcConfig.ClrRoot, + tcConfig.TargetFrameworkDirectories, tcConfig.fsharpBinariesDir) match frameworkTcImportsCache.TryGet key with | Some res -> res diff --git a/src/fsharp/vs/service.fs b/src/fsharp/vs/service.fs index 382ddf8dad4..d5346eb62da 100755 --- a/src/fsharp/vs/service.fs +++ b/src/fsharp/vs/service.fs @@ -1665,7 +1665,7 @@ module internal Parser = let checkForErrors() = (parseResults.ParseHadErrors || errHandler.ErrorCount > 0) // Typecheck is potentially a long running operation. We chop it up here with an Eventually continuation and, at each slice, give a chance // for the client to claim the result as obsolete and have the typecheck abort. - let computation = TypeCheckSingleInputAndFinishEventually(checkForErrors,tcConfig, tcImports, tcGlobals, None, TcResultsSink.WithSink sink, tcState, parsedMainInput) + let computation = TypeCheckOneInputAndFinishEventually(checkForErrors,tcConfig, tcImports, tcGlobals, None, TcResultsSink.WithSink sink, tcState, parsedMainInput) match computation |> Eventually.forceWhile (fun () -> not (isResultObsolete())) with | Some((tcEnvAtEnd,_,typedImplFiles),tcState) -> Some (tcEnvAtEnd, typedImplFiles, tcState) | None -> None // Means 'aborted'