diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index a329635b60..22162611f0 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -342,8 +342,8 @@ type ImportedAssembly = } type AvailableImportedAssembly = - | ResolvedImportedAssembly of ImportedAssembly - | UnresolvedImportedAssembly of string + | ResolvedImportedAssembly of ImportedAssembly * range + | UnresolvedImportedAssembly of string * range type CcuLoadFailureAction = | RaiseError @@ -1024,33 +1024,77 @@ type TcImportsSafeDisposal dispose () #if !NO_TYPEPROVIDERS -// These are hacks in order to allow TcImports to be held as a weak reference inside a type provider. -// The reason is due to older type providers compiled using an older TypeProviderSDK, that SDK used reflection on fields and properties to determine the contract. -// The reflection code has now since been removed, see here: https://github.com/fsprojects/FSharp.TypeProviders.SDK/pull/305. But we still need to work on older type providers. -// One day we can remove these hacks when we deemed most if not all type providers were re-compiled using the newer TypeProviderSDK. -// Yuck. -type TcImportsDllInfoHack = { FileName: string } -and TcImportsWeakHack(tciLock: TcImportsLock, tcImports: WeakReference) = - let mutable dllInfos: TcImportsDllInfoHack list = [] +// TcImports is held as a weak reference inside a TypeProviderConfig. +// +// Due to various historical bugs with the ReferencedAssemblies property of TypeProviderConfig, +// type providers compiled using the TypeProvider SDK have picked up the unfortunate habit of using +// private reflection on the TypeProviderConfig to correctly determine the ReferencedAssemblies. +// These types thus also act as a stable facade supporting exactly the private reflection that is +// used by type providers built with the TypeProvider SDK. +// +// The use of private reflection is highly unfortunate but has historically been the only way to +// unblock several important type providers such as FSharp.Data when the weaknesses in reported +// ReferencedAssemblies were determined. +// +// The use of private reflection was removed from the TypeProvider SDK, see +// https://github.com/fsprojects/FSharp.TypeProviders.SDK/pull/305. But we still need to work on older type providers. +// +// however it was then reinstated +// +// https://github.com/fsprojects/FSharp.TypeProviders.SDK/pull/388 +// +// All known issues TypeProviderConfig::ReferencedAssemblies are now fixed, meaning one day +// we can remove the use of private reflection from the TPSDK (that is, once the F# tooling fixes +// can be assumed to be shipped in all F# tooling where type providers have to load). After that, +// once all type providers are updated, we will no longer need to have this fixed facade. + +/// This acts as a stable type supporting the +type TcImportsDllInfoFacade = { FileName: string } + +type TcImportsWeakFacade(tciLock: TcImportsLock, tcImportsWeak: WeakReference) = + + let mutable dllInfos: TcImportsDllInfoFacade list = [] + + // The name of these fields must not change, see above + do assert (nameof (dllInfos) = "dllInfos") member _.SetDllInfos(value: ImportedBinary list) = tciLock.AcquireLock(fun tcitok -> RequireTcImportsLock(tcitok, dllInfos) - dllInfos <- value |> List.map (fun x -> { FileName = x.FileName })) - member _.Base: TcImportsWeakHack option = - match tcImports.TryGetTarget() with - | true, strong -> - match strong.Base with + let infos = + [ + for x in value do + let info = { FileName = x.FileName } + // The name of this field must not change, see above + assert (nameof (info.FileName) = "FileName") + info + ] + + dllInfos <- infos) + + member this.Base: TcImportsWeakFacade option = + // The name of this property msut not change, see above + assert (nameof (this.Base) = "Base") + + match tcImportsWeak.TryGetTarget() with + | true, tcImports -> + match tcImports.Base with | Some (baseTcImports: TcImports) -> Some baseTcImports.Weak | _ -> None | _ -> None member _.SystemRuntimeContainsType typeName = - match tcImports.TryGetTarget() with - | true, strong -> strong.SystemRuntimeContainsType typeName + match tcImportsWeak.TryGetTarget() with + | true, tcImports -> tcImports.SystemRuntimeContainsType typeName | _ -> false + + member _.AllAssemblyResolutions() = + match tcImportsWeak.TryGetTarget() with + | true, tcImports -> tcImports.AllAssemblyResolutions() + | _ -> [] + #endif /// Represents a table of imported assemblies with their resolutions. /// Is a disposable object, but it is recommended not to explicitly call Dispose unless you absolutely know nothing will be using its contents after the disposal. @@ -1082,7 +1126,7 @@ and [] TcImports let mutable generatedTypeRoots = Dictionary() - let tcImportsWeak = TcImportsWeakHack(tciLock, WeakReference<_> this) + let tcImportsWeak = TcImportsWeakFacade(tciLock, WeakReference<_> this) #endif let disposal = @@ -1140,29 +1184,29 @@ and [] TcImports | None -> false | None -> false - member internal tcImports.Base = + member internal _.Base = CheckDisposed() importsBase - member tcImports.CcuTable = + member _.CcuTable = tciLock.AcquireLock(fun tcitok -> RequireTcImportsLock(tcitok, ccuTable) CheckDisposed() ccuTable) - member tcImports.DllTable = + member _.DllTable = tciLock.AcquireLock(fun tcitok -> RequireTcImportsLock(tcitok, dllTable) CheckDisposed() dllTable) #if !NO_TYPEPROVIDERS - member tcImports.Weak = + member _.Weak = CheckDisposed() tcImportsWeak #endif - member tcImports.RegisterCcu ccuInfo = + member _.RegisterCcu ccuInfo = tciLock.AcquireLock(fun tcitok -> CheckDisposed() RequireTcImportsLock(tcitok, ccuInfos) @@ -1171,7 +1215,7 @@ and [] TcImports // Assembly Ref Resolution: remove this use of ccu.AssemblyName ccuTable <- NameMap.add ccuInfo.FSharpViewOfMetadata.AssemblyName ccuInfo ccuTable) - member tcImports.RegisterDll dllInfo = + member _.RegisterDll dllInfo = tciLock.AcquireLock(fun tcitok -> CheckDisposed() RequireTcImportsLock(tcitok, dllInfos) @@ -1182,7 +1226,7 @@ and [] TcImports #endif dllTable <- NameMap.add (getNameOfScopeRef dllInfo.ILScopeRef) dllInfo dllTable) - member tcImports.GetDllInfos() : ImportedBinary list = + member _.GetDllInfos() : ImportedBinary list = tciLock.AcquireLock(fun tcitok -> CheckDisposed() RequireTcImportsLock(tcitok, dllInfos) @@ -1191,7 +1235,7 @@ and [] TcImports | Some importsBase -> importsBase.GetDllInfos() @ dllInfos | None -> dllInfos) - member tcImports.AllAssemblyResolutions() = + member _.AllAssemblyResolutions() = tciLock.AcquireLock(fun tcitok -> CheckDisposed() RequireTcImportsLock(tcitok, resolutions) @@ -1223,7 +1267,7 @@ and [] TcImports | Some res -> res | None -> error (Error(FSComp.SR.buildCouldNotResolveAssembly assemblyName, m)) - member tcImports.GetImportedAssemblies() = + member _.GetImportedAssemblies() = tciLock.AcquireLock(fun tcitok -> CheckDisposed() RequireTcImportsLock(tcitok, ccuInfos) @@ -1232,7 +1276,7 @@ and [] TcImports | Some importsBase -> List.append (importsBase.GetImportedAssemblies()) ccuInfos | None -> ccuInfos) - member tcImports.GetCcusExcludingBase() = + member _.GetCcusExcludingBase() = tciLock.AcquireLock(fun tcitok -> CheckDisposed() RequireTcImportsLock(tcitok, ccuInfos) @@ -1255,26 +1299,26 @@ and [] TcImports | None -> None match look tcImports with - | Some res -> ResolvedImportedAssembly res + | Some res -> ResolvedImportedAssembly(res, m) | None -> tcImports.ImplicitLoadIfAllowed(ctok, m, assemblyName, lookupOnly) match look tcImports with - | Some res -> ResolvedImportedAssembly res - | None -> UnresolvedImportedAssembly assemblyName + | Some res -> ResolvedImportedAssembly(res, m) + | None -> UnresolvedImportedAssembly(assemblyName, m) member tcImports.FindCcu(ctok, m, assemblyName, lookupOnly) = CheckDisposed() match tcImports.FindCcuInfo(ctok, m, assemblyName, lookupOnly) with - | ResolvedImportedAssembly importedAssembly -> ResolvedCcu(importedAssembly.FSharpViewOfMetadata) - | UnresolvedImportedAssembly assemblyName -> UnresolvedCcu assemblyName + | ResolvedImportedAssembly (importedAssembly, _) -> ResolvedCcu(importedAssembly.FSharpViewOfMetadata) + | UnresolvedImportedAssembly (assemblyName, _) -> UnresolvedCcu assemblyName member tcImports.FindCcuFromAssemblyRef(ctok, m, assemblyRef: ILAssemblyRef) = CheckDisposed() match tcImports.FindCcuInfo(ctok, m, assemblyRef.Name, lookupOnly = false) with - | ResolvedImportedAssembly importedAssembly -> ResolvedCcu(importedAssembly.FSharpViewOfMetadata) + | ResolvedImportedAssembly (importedAssembly, _) -> ResolvedCcu(importedAssembly.FSharpViewOfMetadata) | UnresolvedImportedAssembly _ -> UnresolvedCcu(assemblyRef.QualifiedName) member tcImports.TryFindXmlDocumentationInfo(assemblyName: string) = @@ -1393,7 +1437,7 @@ and [] TcImports // Yes, it is generative true, dllinfo.ProviderGeneratedStaticLinkMap - member tcImports.RecordGeneratedTypeRoot root = + member _.RecordGeneratedTypeRoot root = tciLock.AcquireLock(fun tcitok -> // checking if given ProviderGeneratedType was already recorded before (probably for another set of static parameters) let (ProviderGeneratedType (_, ilTyRef, _)) = root @@ -1407,7 +1451,7 @@ and [] TcImports generatedTypeRoots[ilTyRef] <- (index, root)) - member tcImports.ProviderGeneratedTypeRoots = + member _.ProviderGeneratedTypeRoots = tciLock.AcquireLock(fun tcitok -> RequireTcImportsLock(tcitok, generatedTypeRoots) generatedTypeRoots.Values |> Seq.sortBy fst |> Seq.map snd |> Seq.toList) @@ -1549,7 +1593,7 @@ and [] TcImports // types such as those in method signatures are currently converted on-demand. However ImportILAssembly does have to // convert the types that are constraints in generic parameters, which was the original motivation for making sure that // ImportILAssembly had a tcGlobals available when it really needs it. - member tcImports.GetTcGlobals() : TcGlobals = + member _.GetTcGlobals() : TcGlobals = CheckDisposed() match tcGlobals with @@ -1695,30 +1739,40 @@ and [] TcImports let name = AssemblyName.GetAssemblyName(resolution.resolvedPath) name.Version - let typeProviderEnvironment = - { - ResolutionFolder = tcConfig.implicitIncludeDir - OutputFile = tcConfig.outputFile - ShowResolutionMessages = tcConfig.showExtensionTypeMessages - ReferencedAssemblies = Array.distinct [| for r in tcImportsStrong.AllAssemblyResolutions() -> r.resolvedPath |] - TemporaryFolder = FileSystem.GetTempPathShim() - } - - // The type provider should not hold strong references to disposed - // TcImport objects. So the callbacks provided in the type provider config - // dispatch via a thunk which gets set to a non-resource-capturing - // failing function when the object is disposed. + // Note, this only captures systemRuntimeContainsTypeRef (which captures tcImportsWeak, using name tcImports) let systemRuntimeContainsType = - // NOTE: do not touch this, edit: but we did, we had no choice - TPs cannot hold a strong reference on TcImports "ever". let tcImports = tcImportsWeak + // The name of this captured value must not change, see comments on TcImportsWeakFacade above + assert (nameof (tcImports) = "tcImports") + let mutable systemRuntimeContainsTypeRef = - fun typeName -> tcImports.SystemRuntimeContainsType typeName + (fun typeName -> tcImports.SystemRuntimeContainsType typeName) + // When the tcImports is disposed the systemRuntimeContainsTypeRef thunk is replaced + // with one raising an exception. tcImportsStrong.AttachDisposeTypeProviderAction(fun () -> systemRuntimeContainsTypeRef <- fun _ -> raise (ObjectDisposedException("The type provider has been disposed"))) - fun arg -> systemRuntimeContainsTypeRef arg + (fun arg -> systemRuntimeContainsTypeRef arg) + + // Note, this only captures tcImportsWeak + let mutable getReferencedAssemblies = + (fun () -> [| for r in tcImportsWeak.AllAssemblyResolutions() -> r.resolvedPath |]) + + // When the tcImports is disposed the getReferencedAssemblies thunk is replaced + // with one raising an exception. + tcImportsStrong.AttachDisposeTypeProviderAction(fun () -> + getReferencedAssemblies <- fun _ -> raise (ObjectDisposedException("The type provider has been disposed"))) + + let typeProviderEnvironment = + { + ResolutionFolder = tcConfig.implicitIncludeDir + OutputFile = tcConfig.outputFile + ShowResolutionMessages = tcConfig.showExtensionTypeMessages + GetReferencedAssemblies = (fun () -> [| for r in tcImportsStrong.AllAssemblyResolutions() -> r.resolvedPath |]) + TemporaryFolder = FileSystem.GetTempPathShim() + } let providers = [ @@ -1919,7 +1973,7 @@ and [] TcImports ccuinfo.TypeProviders <- tcImports.ImportTypeProviderExtensions(ctok, tcConfig, fileName, ilScopeRef, attrs, ccu.Contents, invalidateCcu, m) #endif - [ ResolvedImportedAssembly ccuinfo ] + [ ResolvedImportedAssembly(ccuinfo, m) ] phase2 @@ -2059,7 +2113,9 @@ and [] TcImports #if !NO_TYPEPROVIDERS ccuRawDataAndInfos |> List.iter (fun (_, _, phase2) -> phase2 ()) #endif - ccuRawDataAndInfos |> List.map p23 |> List.map ResolvedImportedAssembly + ccuRawDataAndInfos + |> List.map p23 + |> List.map (fun asm -> ResolvedImportedAssembly(asm, m)) phase2 @@ -2160,10 +2216,10 @@ and [] TcImports }) |> runMethod - let dllinfos, phase2s = results |> Array.choose id |> List.ofArray |> List.unzip + let _dllinfos, phase2s = results |> Array.choose id |> List.ofArray |> List.unzip fixupOrphanCcus () - let ccuinfos = (List.collect (fun phase2 -> phase2 ()) phase2s) - return dllinfos, ccuinfos + let ccuinfos = List.collect (fun phase2 -> phase2 ()) phase2s + return ccuinfos } /// Note that implicit loading is not used for compilations from MSBuild, which passes ``--noframework`` @@ -2213,7 +2269,7 @@ and [] TcImports #endif /// Only used by F# Interactive - member tcImports.TryFindExistingFullyQualifiedPathBySimpleAssemblyName simpleAssemName : string option = + member _.TryFindExistingFullyQualifiedPathBySimpleAssemblyName simpleAssemName : string option = tciLock.AcquireLock(fun tcitok -> RequireTcImportsLock(tcitok, resolutions) @@ -2221,14 +2277,14 @@ and [] TcImports |> Option.map (fun r -> r.resolvedPath)) /// Only used by F# Interactive - member tcImports.TryFindExistingFullyQualifiedPathByExactAssemblyRef(assemblyRef: ILAssemblyRef) : string option = + member _.TryFindExistingFullyQualifiedPathByExactAssemblyRef(assemblyRef: ILAssemblyRef) : string option = tciLock.AcquireLock(fun tcitok -> RequireTcImportsLock(tcitok, resolutions) resolutions.TryFindByExactILAssemblyRef assemblyRef |> Option.map (fun r -> r.resolvedPath)) - member tcImports.TryResolveAssemblyReference + member _.TryResolveAssemblyReference ( ctok, assemblyReference: AssemblyReference, @@ -2325,7 +2381,7 @@ and [] TcImports let primaryScopeRef = match primaryAssem with - | _, [ ResolvedImportedAssembly ccu ] -> ccu.FSharpViewOfMetadata.ILScopeRef + | [ ResolvedImportedAssembly (ccu, _) ] -> ccu.FSharpViewOfMetadata.ILScopeRef | _ -> failwith "primaryScopeRef - unexpected" let resolvedAssemblies = tcResolutions.GetAssemblyResolutions() @@ -2386,7 +2442,7 @@ and [] TcImports match resolvedAssemblyRef with | Some coreLibraryResolution -> match! frameworkTcImports.RegisterAndImportReferencedAssemblies(ctok, [ coreLibraryResolution ]) with - | _, [ ResolvedImportedAssembly fslibCcuInfo ] -> + | [ ResolvedImportedAssembly (fslibCcuInfo, _) ] -> return fslibCcuInfo.FSharpViewOfMetadata, fslibCcuInfo.ILScopeRef | _ -> return @@ -2440,7 +2496,7 @@ and [] TcImports return tcGlobals, frameworkTcImports } - member tcImports.ReportUnresolvedAssemblyReferences knownUnresolved = + member _.ReportUnresolvedAssemblyReferences knownUnresolved = // Report that an assembly was not resolved. let reportAssemblyNotResolved (file, originalReferences: AssemblyReference list) = originalReferences @@ -2500,43 +2556,34 @@ and [] TcImports } interface IDisposable with - member tcImports.Dispose() = dispose () + member _.Dispose() = dispose () override tcImports.ToString() = "TcImports(...)" /// Process #r in F# Interactive. /// Adds the reference to the tcImports and add the ccu to the type checking environment. -let RequireDLL (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, referenceRange, file) = - let resolutions = - CommitOperationResult( - tcImports.TryResolveAssemblyReference( - ctok, - AssemblyReference(referenceRange, file, None), - ResolveAssemblyReferenceMode.ReportErrors - ) - ) +let RequireReferences (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, resolutions) = - let dllinfos, ccuinfos = + let ccuinfos = tcImports.RegisterAndImportReferencedAssemblies(ctok, resolutions) |> NodeCode.RunImmediateWithoutCancellation let asms = ccuinfos |> List.map (function - | ResolvedImportedAssembly asm -> asm - | UnresolvedImportedAssembly assemblyName -> - error (Error(FSComp.SR.buildCouldNotResolveAssemblyRequiredByFile (assemblyName, file), referenceRange))) + | ResolvedImportedAssembly (asm, m) -> asm, m + | UnresolvedImportedAssembly (assemblyName, m) -> error (Error(FSComp.SR.buildCouldNotResolveAssembly (assemblyName), m))) let g = tcImports.GetTcGlobals() let amap = tcImports.GetImportMap() let _openDecls, tcEnv = (tcEnv, asms) - ||> List.collectFold (fun tcEnv asm -> + ||> List.collectFold (fun tcEnv (asm, m) -> AddCcuToTcEnv( g, amap, - referenceRange, + m, tcEnv, thisAssemblyName, asm.FSharpViewOfMetadata, @@ -2544,4 +2591,6 @@ let RequireDLL (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, referenceRa asm.AssemblyInternalsVisibleToAttributes )) - tcEnv, (dllinfos, asms) + let asms = asms |> List.map fst + + tcEnv, asms diff --git a/src/Compiler/Driver/CompilerImports.fsi b/src/Compiler/Driver/CompilerImports.fsi index d6be5bbd60..30bb4333f7 100644 --- a/src/Compiler/Driver/CompilerImports.fsi +++ b/src/Compiler/Driver/CompilerImports.fsi @@ -208,13 +208,12 @@ type TcImports = static member BuildTcImports: tcConfigP: TcConfigProvider * dependencyProvider: DependencyProvider -> NodeCode -/// Process #r in F# Interactive. +/// Process a group of #r in F# Interactive. /// Adds the reference to the tcImports and add the ccu to the type checking environment. -val RequireDLL: +val RequireReferences: ctok: CompilationThreadToken * tcImports: TcImports * tcEnv: TcEnv * thisAssemblyName: string * - referenceRange: range * - file: string -> - TcEnv * (ImportedBinary list * ImportedAssembly list) + resolutions: AssemblyResolution list -> + TcEnv * ImportedAssembly list diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index 703e3483f1..db3f30d41b 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fs +++ b/src/Compiler/Driver/ParseAndCheckInputs.fs @@ -484,7 +484,6 @@ let TestInteractionParserAndExit (tokenizer: Tokenizer, lexbuf: LexBuffer, while true do match (Parser.interaction (fun _ -> tokenizer ()) lexbuf) with | ParsedScriptInteraction.Definitions (l, m) -> printfn "Parsed OK, got %d defs @ %a" l.Length outputRange m - | ParsedScriptInteraction.HashDirective (_, m) -> printfn "Parsed OK, got hash @ %a" outputRange m exiter.Exit 0 diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 48b3905558..a298af5490 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -55,7 +55,6 @@ tupleRequiredInAbstractMethod,"\nA tuple type is required for one or more argume 226,buildInvalidSourceFileExtensionUpdated,"The file extension of '%s' is not recognized. Source files must have extension .fs, .fsi, .fsx or .fsscript" 226,buildInvalidSourceFileExtensionML,"The file extension of '%s' is not recognized. Source files must have extension .fs, .fsi, .fsx or .fsscript. To enable the deprecated use of .ml or .mli extensions, use '--langversion:5.0' and '--mlcompatibility'." 227,buildCouldNotResolveAssembly,"Could not resolve assembly '%s'" -228,buildCouldNotResolveAssemblyRequiredByFile,"Could not resolve assembly '%s' required by '%s'" 229,buildErrorOpeningBinaryFile,"Error opening binary file '%s': %s" 231,buildDifferentVersionMustRecompile,"The F#-compiled DLL '%s' needs to be recompiled to be used with this version of F#" 232,buildInvalidHashIDirective,"Invalid directive. Expected '#I \"\"'." diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj index ea73cd1ad7..98a87e8d73 100644 --- a/src/Compiler/FSharp.Compiler.Service.fsproj +++ b/src/Compiler/FSharp.Compiler.Service.fsproj @@ -13,7 +13,7 @@ FSharp.Compiler.Service true $(DefineConstants);COMPILER - $(DefineConstants);USE_SHIPPED_FSCORE + $(DefineConstants);FSHARPCORE_USE_PACKAGE $(OtherFlags) --extraoptimizationloops:1 $(OtherFlags) --warnon:1182 diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 9ad441ddc2..6552c6a62d 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -1199,7 +1199,7 @@ type internal FsiConsoleInput(fsi: FsiEvaluationSessionHostConfig, fsiOptions: F type FsiInteractionStepStatus = | CtrlC | EndOfFile - | Completed of option + | Completed of FsiValue option | CompletedWithAlreadyReportedError | CompletedWithReportedError of exn @@ -1349,7 +1349,9 @@ type internal FsiDynamicCompiler( let dynamicAssemblies = ResizeArray() - let mutable needsPackageResolution = false + let mutable hasDelayedDependencyManagerText = false + + let mutable delayedReferences = ResizeArray<_>() let generateDebugInfo = tcConfigB.debuginfo @@ -1369,6 +1371,8 @@ type internal FsiDynamicCompiler( let infoReader = InfoReader(tcGlobals,tcImports.GetImportMap()) + let reportedAssemblies = Dictionary() + /// Add attributes let CreateModuleFragment (tcConfigB: TcConfigBuilder, dynamicCcuName, codegenResults) = if progress then fprintfn fsiConsoleOutput.Out "Creating main module..." @@ -1879,9 +1883,13 @@ type internal FsiDynamicCompiler( // let optValue = istate.ilxGenerator.LookupGeneratedValue(valuePrinter.GetEvaluationContext(istate.emEnv), vref.Deref) - match optValue with - | Some (res, ty) -> istate, Completed(Some(FsiValue(res, ty, FSharpType(tcGlobals, istate.tcState.Ccu, istate.tcState.CcuSig, istate.tcImports, vref.Type)))) - | _ -> istate, Completed None + + let fsiValue = + match optValue with + | Some (res, ty) -> Some(FsiValue(res, ty, FSharpType(tcGlobals, istate.tcState.Ccu, istate.tcState.CcuSig, istate.tcImports, vref.Type))) + | _ -> None + + istate, Completed fsiValue // Return the interactive state. | _ -> istate, Completed None @@ -1905,30 +1913,90 @@ type internal FsiDynamicCompiler( let breakStatement = SynExpr.App (ExprAtomicFlag.Atomic, false, methCall, args, m) SynModuleDecl.Expr(breakStatement, m) - member _.EvalRequireReference (ctok, istate, m, path) = + /// Resolve and register an assembly reference, delaying the actual addition of the reference + /// to tcImports until a whole set of references has been collected. + /// + /// That is, references are collected across a group of #r declarations and only added to the + /// tcImports state once all are collected. + member _.AddDelayedReference (ctok, path, show, m) = + + // Check the file can be resolved if FileSystem.IsInvalidPathShim(path) then - error(Error(FSIstrings.SR.fsiInvalidAssembly(path),m)) - // Check the file can be resolved before calling requireDLLReference - let resolutions = tcImports.ResolveAssemblyReference(ctok, AssemblyReference(m,path,None), ResolveAssemblyReferenceMode.ReportErrors) - tcConfigB.AddReferencedAssemblyByPath(m,path) + error(Error(FSIstrings.SR.fsiInvalidAssembly(path), m)) + + // Do the resolution + let resolutions = + tcImports.ResolveAssemblyReference(ctok, AssemblyReference(m,path,None), ResolveAssemblyReferenceMode.ReportErrors) + + // Delay the addition of the assembly to the interactive state + delayedReferences.Add((path, resolutions, show, m)) + + /// Indicates if there are delayed assembly additions to be processed. + member _.HasDelayedReferences = delayedReferences.Count > 0 + + /// Process any delayed assembly additions. + member _.ProcessDelayedReferences (ctok, istate) = + + // Grab the dealyed assembly reference additions + let refs = delayedReferences |> Seq.toList + delayedReferences.Clear() + + // Print the explicit assembly resolutions. Only for explicit '#r' in direct inputs, not those + // in #load files. This means those resulting from nuget package resolution are not shown. + for (_, resolutions, show, _) in refs do + if show then + for ar in resolutions do + let format = + if tcConfigB.shadowCopyReferences then + let resolvedPath = ar.resolvedPath.ToUpperInvariant() + let fileTime = FileSystem.GetLastWriteTimeShim(resolvedPath) + match reportedAssemblies.TryGetValue resolvedPath with + | false, _ -> + reportedAssemblies.Add(resolvedPath, fileTime) + FSIstrings.SR.fsiDidAHashr(ar.resolvedPath) + | true, time when time <> fileTime -> + FSIstrings.SR.fsiDidAHashrWithStaleWarning(ar.resolvedPath) + | _ -> + FSIstrings.SR.fsiDidAHashr(ar.resolvedPath) + else + FSIstrings.SR.fsiDidAHashrWithLockWarning(ar.resolvedPath) + + fsiConsoleOutput.uprintnfnn "%s" format + + // Collect the overall resolutions + let resolutions = + [ for (_, resolutions, _, _) in refs do + yield! resolutions ] + + // Add then to the config. + for (path, _, _, m) in refs do + tcConfigB.AddReferencedAssemblyByPath(m, path) + let tcState = istate.tcState - let tcEnv,(_dllinfos,ccuinfos) = + + let tcEnv, asms = try - RequireDLL (ctok, tcImports, tcState.TcEnvFromImpls, dynamicCcuName, m, path) + RequireReferences (ctok, tcImports, tcState.TcEnvFromImpls, dynamicCcuName, resolutions) with _ -> - tcConfigB.RemoveReferencedAssemblyByPath(m,path) + for (path, _, _, m) in refs do + tcConfigB.RemoveReferencedAssemblyByPath(m,path) reraise() - resolutions, - { addCcusToIncrementalEnv istate ccuinfos with tcState = tcState.NextStateAfterIncrementalFragment(tcEnv) } - member _.EvalDependencyManagerTextFragment (packageManager:IDependencyManagerProvider, lt, m, path: string) = + let istate = { addCcusToIncrementalEnv istate asms with tcState = tcState.NextStateAfterIncrementalFragment(tcEnv) } + + istate + // Dependency manager text is collected across a group of #r and #i declarations and + // only actually processed once all are collected. + member _.AddDelayedDependencyManagerText (packageManager:IDependencyManagerProvider, lt, m, path: string) = tcConfigB.packageManagerLines <- PackageManagerLine.AddLineWithKey packageManager.Key lt path m tcConfigB.packageManagerLines - needsPackageResolution <- true + hasDelayedDependencyManagerText <- true - member fsiDynamicCompiler.CommitDependencyManagerText (ctok, istate: FsiDynamicCompilerState, lexResourceManager, diagnosticsLogger) = - if not needsPackageResolution then istate else - needsPackageResolution <- false + member _.HasDelayedDependencyManagerText = hasDelayedDependencyManagerText + + member fsiDynamicCompiler.ProcessDelayedDependencyManagerText (ctok, istate: FsiDynamicCompilerState, lexResourceManager, diagnosticsLogger) = + if not hasDelayedDependencyManagerText then istate else + hasDelayedDependencyManagerText <- false (istate, tcConfigB.packageManagerLines) ||> Seq.fold (fun istate kv -> let (KeyValue(packageManagerKey, packageManagerLines)) = kv @@ -1990,38 +2058,47 @@ type internal FsiDynamicCompiler( reraise () ) - member fsiDynamicCompiler.ProcessMetaCommandsFromInputAsInteractiveCommands(ctok, istate, sourceFile, inp) = + member fsiDynamicCompiler.PartiallyProcessReferenceOrPackageIncudePathDirective (ctok, istate, directiveKind, path, show, m) = + let dm = fsiOptions.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) + match dm with + | Null, Null -> + // error already reported + istate, CompletedWithAlreadyReportedError + + | _, NonNull dependencyManager -> + if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then + fsiDynamicCompiler.AddDelayedDependencyManagerText(dependencyManager, directiveKind, m, path) + istate, Completed None + else + errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) + istate, Completed None + + | _, _ when directiveKind = Directive.Include -> + errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) + istate, Completed None + + | NonNull p, Null -> + let path = + if String.IsNullOrWhiteSpace(p) then "" + else p + + fsiDynamicCompiler.AddDelayedReference(ctok, path, show, m) + + istate, Completed None + + /// Scrape #r, #I and package manager commands from a #load + member fsiDynamicCompiler.ProcessMetaCommandsFromParsedInputAsInteractiveCommands(ctok, istate: FsiDynamicCompilerState, sourceFile, input) = WithImplicitHome (tcConfigB, directoryName sourceFile) (fun () -> ProcessMetaCommandsFromInput ((fun st (m,nm) -> tcConfigB.TurnWarningOff(m,nm); st), (fun st (m, path, directive) -> - - let dm = tcImports.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) - - match dm with - | _, NonNull dependencyManager -> - if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - fsiDynamicCompiler.EvalDependencyManagerTextFragment (dependencyManager, directive, m, path) - st - else - errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) - st - - | _, _ when directive = Directive.Include -> - errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) - st - - // #r "Assembly" - | NonNull path, _ -> - snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, path)) - - | Null, Null -> - st + let st, _ = fsiDynamicCompiler.PartiallyProcessReferenceOrPackageIncudePathDirective (ctok, st, directive, path, false, m) + st ), (fun _ _ -> ())) - (tcConfigB, inp, Path.GetDirectoryName sourceFile, istate)) + (tcConfigB, input, Path.GetDirectoryName sourceFile, istate)) member fsiDynamicCompiler.EvalSourceFiles(ctok, istate, m, sourceFiles, lexResourceManager, diagnosticsLogger: DiagnosticsLogger) = let tcConfig = TcConfig.Create(tcConfigB,validate=false) @@ -2069,7 +2146,10 @@ type internal FsiDynamicCompiler( |> List.unzip diagnosticsLogger.AbortOnError(fsiConsoleOutput); - let istate = (istate, sourceFiles, inputs) |||> List.fold2 (fun istate sourceFile input -> fsiDynamicCompiler.ProcessMetaCommandsFromInputAsInteractiveCommands(ctok, istate, sourceFile, input)) + let istate = (istate, sourceFiles, inputs) |||> List.fold2 (fun istate sourceFile input -> fsiDynamicCompiler.ProcessMetaCommandsFromParsedInputAsInteractiveCommands(ctok, istate, sourceFile, input)) + + let istate = fsiDynamicCompiler.ProcessDelayedReferences (ctok, istate) + fsiDynamicCompiler.EvalParsedSourceFiles (ctok, diagnosticsLogger, istate, inputs, m) member _.GetBoundValues istate = @@ -2291,13 +2371,13 @@ type internal FsiInterruptController( exitViaKillThread <- false // don't exit via kill thread member _.PosixInvoke(n:int) = - // we run this code once with n = -1 to make sure it is JITted before execution begins - // since we are not allowed to JIT a signal handler. This also ensures the "PosixInvoke" - // method is not eliminated by dead-code elimination - if n >= 0 then - posixReinstate() - stdinInterruptState <- StdinEOFPermittedBecauseCtrlCRecentlyPressed - killThreadRequest <- if (interruptAllowed = InterruptCanRaiseException) then ThreadAbortRequest else PrintInterruptRequest + // we run this code once with n = -1 to make sure it is JITted before execution begins + // since we are not allowed to JIT a signal handler. This also ensures the "PosixInvoke" + // method is not eliminated by dead-code elimination + if n >= 0 then + posixReinstate() + stdinInterruptState <- StdinEOFPermittedBecauseCtrlCRecentlyPressed + killThreadRequest <- if (interruptAllowed = InterruptCanRaiseException) then ThreadAbortRequest else PrintInterruptRequest //---------------------------------------------------------------------------- // assembly finder @@ -2571,6 +2651,11 @@ type FsiStdinLexerProvider member _.CreateBufferLexer (sourceFileName, lexbuf, diagnosticsLogger) = CreateLexerForLexBuffer (sourceFileName, lexbuf, diagnosticsLogger) +[] +type InteractionGroup = + | Definitions of defns: SynModuleDecl list * range: range + + | HashDirectives of hashDirective: ParsedHashDirective list //---------------------------------------------------------------------------- // Process one parsed interaction. This runs on the GUI thread. @@ -2591,8 +2676,6 @@ type FsiInteractionProcessor initialInteractiveState ) = - let referencedAssemblies = Dictionary() - let mutable currState = initialInteractiveState let event = Control.Event() let setCurrState s = currState <- s; event.Trigger() @@ -2634,7 +2717,6 @@ type FsiInteractionProcessor else error(Error(FSIstrings.SR.fsiDirectoryDoesNotExist(path),m)) - /// Parse one interaction. Called on the parser thread. let ParseInteraction (tokenizer:LexFilter.LexFilter) = let mutable lastToken = Parser.ELSE // Any token besides SEMICOLON_SEMICOLON will do for initial value @@ -2662,217 +2744,239 @@ type FsiInteractionProcessor stopProcessingRecovery e range0 None - /// Execute a single parsed interaction. Called on the GUI/execute/main thread. - let ExecInteraction (ctok, tcConfig:TcConfig, istate, action:ParsedScriptInteraction, diagnosticsLogger: DiagnosticsLogger) = - let packageManagerDirective directive path m = - let dm = fsiOptions.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) - match dm with - | Null, Null -> - // error already reported - istate, CompletedWithAlreadyReportedError - - | _, NonNull dependencyManager -> - if tcConfig.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - fsiDynamicCompiler.EvalDependencyManagerTextFragment(dependencyManager, directive, m, path) - istate, Completed None - else - errorR(Error(FSComp.SR.packageManagementRequiresVFive(), m)) - istate, Completed None - - | _, _ when directive = Directive.Include -> - errorR(Error(FSComp.SR.poundiNotSupportedByRegisteredDependencyManagers(), m)) - istate,Completed None - - | NonNull p, Null -> - let path = - if String.IsNullOrWhiteSpace(p) then "" - else p - let resolutions,istate = fsiDynamicCompiler.EvalRequireReference(ctok, istate, m, path) - resolutions |> List.iter (fun ar -> - let format = - if tcConfig.shadowCopyReferences then - let resolvedPath = ar.resolvedPath.ToUpperInvariant() - let fileTime = FileSystem.GetLastWriteTimeShim(resolvedPath) - match referencedAssemblies.TryGetValue resolvedPath with - | false, _ -> - referencedAssemblies.Add(resolvedPath, fileTime) - FSIstrings.SR.fsiDidAHashr(ar.resolvedPath) - | true, time when time <> fileTime -> - FSIstrings.SR.fsiDidAHashrWithStaleWarning(ar.resolvedPath) - | _ -> - FSIstrings.SR.fsiDidAHashr(ar.resolvedPath) - else - FSIstrings.SR.fsiDidAHashrWithLockWarning(ar.resolvedPath) - fsiConsoleOutput.uprintnfnn "%s" format) - istate,Completed None - - istate |> InteractiveCatch diagnosticsLogger (fun istate -> - match action with - | ParsedScriptInteraction.Definitions ([], _) -> - let istate = fsiDynamicCompiler.CommitDependencyManagerText(ctok, istate, lexResourceManager, diagnosticsLogger) - istate,Completed None - - | ParsedScriptInteraction.Definitions ([SynModuleDecl.Expr(expr, _)], _) -> - let istate = fsiDynamicCompiler.CommitDependencyManagerText(ctok, istate, lexResourceManager, diagnosticsLogger) - fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, expr) + /// Partially process a hash directive, leaving state in packageManagerLines and required assemblies + let PartiallyProcessHashDirective (ctok, istate, hash, diagnosticsLogger: DiagnosticsLogger) = + match hash with + | ParsedHashDirective("load", ParsedHashDirectiveArguments sourceFiles, m) -> + let istate = fsiDynamicCompiler.EvalSourceFiles (ctok, istate, m, sourceFiles, lexResourceManager, diagnosticsLogger) + istate, Completed None - | ParsedScriptInteraction.Definitions (defs,_) -> - let istate = fsiDynamicCompiler.CommitDependencyManagerText(ctok, istate, lexResourceManager, diagnosticsLogger) - fsiDynamicCompiler.EvalParsedDefinitions (ctok, diagnosticsLogger, istate, true, false, defs) + | ParsedHashDirective(("reference" | "r"), ParsedHashDirectiveArguments [path], m) -> + fsiDynamicCompiler.PartiallyProcessReferenceOrPackageIncudePathDirective (ctok, istate, Directive.Resolution, path, true, m) - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("load", ParsedHashDirectiveArguments sourceFiles, m), _) -> - let istate = fsiDynamicCompiler.CommitDependencyManagerText(ctok, istate, lexResourceManager, diagnosticsLogger) - fsiDynamicCompiler.EvalSourceFiles (ctok, istate, m, sourceFiles, lexResourceManager, diagnosticsLogger),Completed None + | ParsedHashDirective("i", ParsedHashDirectiveArguments [path], m) -> + fsiDynamicCompiler.PartiallyProcessReferenceOrPackageIncudePathDirective (ctok, istate, Directive.Include, path, true, m) - | ParsedScriptInteraction.HashDirective (ParsedHashDirective(("reference" | "r"), ParsedHashDirectiveArguments [path], m), _) -> - packageManagerDirective Directive.Resolution path m + | ParsedHashDirective("I", ParsedHashDirectiveArguments [path], m) -> + tcConfigB.AddIncludePath (m, path, tcConfigB.implicitIncludeDir) + let tcConfig = TcConfig.Create(tcConfigB,validate=false) + fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiDidAHashI(tcConfig.MakePathAbsolute path)) + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("i", ParsedHashDirectiveArguments [path], m), _) -> - packageManagerDirective Directive.Include path m + | ParsedHashDirective("cd", ParsedHashDirectiveArguments [path], m) -> + ChangeDirectory path m + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("I", ParsedHashDirectiveArguments [path], m), _) -> - tcConfigB.AddIncludePath (m, path, tcConfig.implicitIncludeDir) - fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiDidAHashI(tcConfig.MakePathAbsolute path)) - istate, Completed None + | ParsedHashDirective("silentCd", ParsedHashDirectiveArguments [path], m) -> + ChangeDirectory path m + fsiConsolePrompt.SkipNext() (* "silent" directive *) + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("cd", ParsedHashDirectiveArguments [path], m), _) -> - ChangeDirectory path m - istate, Completed None + | ParsedHashDirective("dbgbreak", [], _) -> + let istate = {istate with debugBreak = true} + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("silentCd", ParsedHashDirectiveArguments [path], m), _) -> - ChangeDirectory path m - fsiConsolePrompt.SkipNext() (* "silent" directive *) - istate, Completed None - - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("dbgbreak", [], _), _) -> - {istate with debugBreak = true}, Completed None - - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("time", [], _), _) -> - if istate.timing then - fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiTurnedTimingOff()) - else - fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiTurnedTimingOn()) - {istate with timing = not istate.timing}, Completed None + | ParsedHashDirective("time", [], _) -> + if istate.timing then + fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiTurnedTimingOff()) + else + fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiTurnedTimingOn()) + let istate = {istate with timing = not istate.timing} + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("time", ParsedHashDirectiveArguments ["on" | "off" as v], _), _) -> - if v <> "on" then - fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiTurnedTimingOff()) - else - fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiTurnedTimingOn()) - {istate with timing = (v = "on")}, Completed None + | ParsedHashDirective("time", ParsedHashDirectiveArguments ["on" | "off" as v], _) -> + if v <> "on" then + fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiTurnedTimingOff()) + else + fsiConsoleOutput.uprintnfnn "%s" (FSIstrings.SR.fsiTurnedTimingOn()) + let istate = {istate with timing = (v = "on")} + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("nowarn", ParsedHashDirectiveArguments numbers, m), _) -> - List.iter (fun (d:string) -> tcConfigB.TurnWarningOff(m, d)) numbers - istate, Completed None + | ParsedHashDirective("nowarn", ParsedHashDirectiveArguments numbers, m) -> + List.iter (fun (d:string) -> tcConfigB.TurnWarningOff(m, d)) numbers + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("terms", [], _), _) -> - tcConfigB.showTerms <- not tcConfig.showTerms - istate, Completed None + | ParsedHashDirective("terms", [], _) -> + tcConfigB.showTerms <- not tcConfigB.showTerms + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("types", [], _), _) -> - fsiOptions.ShowTypes <- not fsiOptions.ShowTypes - istate, Completed None + | ParsedHashDirective("types", [], _) -> + fsiOptions.ShowTypes <- not fsiOptions.ShowTypes + istate, Completed None - #if DEBUG - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("ilcode", [], _m), _) -> - fsiOptions.ShowILCode <- not fsiOptions.ShowILCode; - istate, Completed None +#if DEBUG + | ParsedHashDirective("ilcode", [], _m) -> + fsiOptions.ShowILCode <- not fsiOptions.ShowILCode; + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("info", [], _m), _) -> - PrintOptionInfo tcConfigB - istate, Completed None - #endif - | ParsedScriptInteraction.HashDirective (ParsedHashDirective(("clear"), [], _), _) -> - fsiOptions.ClearScreen() - istate, Completed None + | ParsedHashDirective("info", [], _m) -> + PrintOptionInfo tcConfigB + istate, Completed None +#endif + | ParsedHashDirective(("clear"), [], _) -> + fsiOptions.ClearScreen() + istate, Completed None - | ParsedScriptInteraction.HashDirective (ParsedHashDirective(("q" | "quit"), [], _), _) -> - fsiInterruptController.Exit() + | ParsedHashDirective(("q" | "quit"), [], _) -> + fsiInterruptController.Exit() + + | ParsedHashDirective("help", [], m) -> + fsiOptions.ShowHelp(m) + istate, Completed None + + | ParsedHashDirective(c, ParsedHashDirectiveArguments arg, m) -> + warning(Error((FSComp.SR.fsiInvalidDirective(c, String.concat " " arg)), m)) + istate, Completed None + + /// Most functions return a step status - this decides whether to continue and propogates the + /// last value produced + let ProcessStepStatus (istate, cont) lastResult f = + match cont with + | Completed newResult -> f newResult istate + // stop on error + | CompletedWithReportedError e -> istate, CompletedWithReportedError e + // stop on error + | CompletedWithAlreadyReportedError -> istate, CompletedWithAlreadyReportedError + // stop on EOF + | EndOfFile -> istate, Completed lastResult + // stop on CtrlC + | CtrlC -> istate, CtrlC + + /// Execute a group of interactions. Called on the GUI/execute/main thread. + /// The action is either a group of definitions or a group of hash-references. + let ExecuteInteractionGroup (ctok, istate, action: InteractionGroup, diagnosticsLogger: DiagnosticsLogger) = + istate |> InteractiveCatch diagnosticsLogger (fun istate -> + let rec loop istate action = + // These following actions terminate a dependency manager and/or references group + // - nothing left to do + // - a group of non-hash definitions + // - a #load + match action with + | InteractionGroup.Definitions _ + | InteractionGroup.HashDirectives [] + | InteractionGroup.HashDirectives (ParsedHashDirective("load", _, _) :: _) -> + if fsiDynamicCompiler.HasDelayedDependencyManagerText then + let istate = fsiDynamicCompiler.ProcessDelayedDependencyManagerText(ctok, istate, lexResourceManager, diagnosticsLogger) + loop istate action + elif fsiDynamicCompiler.HasDelayedReferences then + let istate = fsiDynamicCompiler.ProcessDelayedReferences (ctok, istate) + loop istate action + else + match action with + | InteractionGroup.Definitions ([], _) + | InteractionGroup.HashDirectives [] -> + istate,Completed None + + | InteractionGroup.Definitions ([SynModuleDecl.Expr(expr, _)], _) -> + fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, expr) + + | InteractionGroup.Definitions (defs,_) -> + fsiDynamicCompiler.EvalParsedDefinitions (ctok, diagnosticsLogger, istate, true, false, defs) + + | InteractionGroup.HashDirectives (hash :: rest) -> + let status = PartiallyProcessHashDirective (ctok, istate, hash, diagnosticsLogger) + ProcessStepStatus status None (fun _ istate -> + loop istate (InteractionGroup.HashDirectives rest) + ) + + // Other hash directives do not terminate a dependency manager and/or references group + | InteractionGroup.HashDirectives (hash :: rest) -> + let status = PartiallyProcessHashDirective (ctok, istate, hash, diagnosticsLogger) + ProcessStepStatus status None (fun _ istate -> + loop istate (InteractionGroup.HashDirectives rest) + ) + + loop istate action + ) - | ParsedScriptInteraction.HashDirective (ParsedHashDirective("help", [], m), _) -> - fsiOptions.ShowHelp(m) - istate, Completed None + let isDefHash = function SynModuleDecl.HashDirective _ -> true | _ -> false - | ParsedScriptInteraction.HashDirective (ParsedHashDirective(c, ParsedHashDirectiveArguments arg, m), _) -> - warning(Error((FSComp.SR.fsiInvalidDirective(c, String.concat " " arg)), m)) - istate, Completed None - ) + // Only add automatic debugger breaks before 'let' or 'do' expressions with sequence points + let isBreakable def = + match def with + | SynModuleDecl.Let (bindings=SynBinding(debugPoint=DebugPointAtBinding.Yes _) :: _) -> true + | _ -> false /// Execute a single parsed interaction which may contain multiple items to be executed /// independently, because some are #directives. Called on the GUI/execute/main thread. /// /// #directive comes through with other definitions as a SynModuleDecl.HashDirective. /// We split these out for individual processing. - let rec execParsedInteractions (ctok, tcConfig, istate, action, diagnosticsLogger: DiagnosticsLogger, lastResult: FsiInteractionStepStatus option, cancellationToken: CancellationToken) = + let rec ExecuteParsedInteractionInGroups (ctok, istate, synInteraction, diagnosticsLogger: DiagnosticsLogger, lastResult: FsiValue option, cancellationToken: CancellationToken) = cancellationToken.ThrowIfCancellationRequested() - let action,nextAction,istate = - match action with + let group, others, istate = + match synInteraction with | None -> None,None,istate - | Some (ParsedScriptInteraction.HashDirective _) -> action,None,istate + | Some (ParsedScriptInteraction.Definitions (defs,m)) -> + match defs with + | [] -> + None, None, istate - | Some (ParsedScriptInteraction.Definitions ([],_)) -> None,None,istate + | SynModuleDecl.HashDirective _ :: _ -> + let hashes = List.takeWhile isDefHash defs |> List.choose (function (SynModuleDecl.HashDirective(hash, _))-> Some(hash) | _ -> None) + let defsB = List.skipWhile isDefHash defs - | Some (ParsedScriptInteraction.Definitions (SynModuleDecl.HashDirective(hash,mh) :: defs,m)) -> - Some (ParsedScriptInteraction.HashDirective(hash,mh)),Some (ParsedScriptInteraction.Definitions(defs,m)),istate + let group = InteractionGroup.HashDirectives(hashes) + let others = ParsedScriptInteraction.Definitions(defsB, m) + Some group, Some others, istate - | Some (ParsedScriptInteraction.Definitions (defs,m)) -> - let isDefHash = function SynModuleDecl.HashDirective _ -> true | _ -> false - let isBreakable def = - // only add automatic debugger breaks before 'let' or 'do' expressions with sequence points - match def with - | SynModuleDecl.Let (bindings=SynBinding(debugPoint=DebugPointAtBinding.Yes _) :: _) -> true - | _ -> false - let defsA = Seq.takeWhile (isDefHash >> not) defs |> Seq.toList - let defsB = Seq.skipWhile (isDefHash >> not) defs |> Seq.toList - - // If user is debugging their script interactively, inject call - // to Debugger.Break() at the first "breakable" line. - // Update istate so that more Break() calls aren't injected when recursing - let defsA,istate = - if istate.debugBreak then - let preBreak = Seq.takeWhile (isBreakable >> not) defsA |> Seq.toList - let postBreak = Seq.skipWhile (isBreakable >> not) defsA |> Seq.toList - match postBreak with - | h :: _ -> preBreak @ (fsiDynamicCompiler.CreateDebuggerBreak(h.Range) :: postBreak), { istate with debugBreak = false } - | _ -> defsA, istate - else defsA,istate - - // When the last declaration has a shape of DoExp (i.e., non-binding), - // transform it to a shape of "let it = ", so we can refer it. - let defsA = - if not (isNil defsB) then defsA else - match defsA with - | [] -> defsA - | [_] -> defsA - | _ -> - match List.rev defsA with - | SynModuleDecl.Expr(expr, _) :: rest -> (rest |> List.rev) @ (fsiDynamicCompiler.BuildItBinding expr) - | _ -> defsA - - Some (ParsedScriptInteraction.Definitions(defsA,m)),Some (ParsedScriptInteraction.Definitions(defsB,m)),istate - - match action, lastResult with - | None, Some prev -> assert nextAction.IsNone; istate, prev - | None,_ -> assert nextAction.IsNone; istate, Completed None - | Some action, _ -> - let istate,cont = ExecInteraction (ctok, tcConfig, istate, action, diagnosticsLogger) - match cont with - | Completed _ -> execParsedInteractions (ctok, tcConfig, istate, nextAction, diagnosticsLogger, Some cont, cancellationToken) - | CompletedWithReportedError e -> istate,CompletedWithReportedError e (* drop nextAction on error *) - | CompletedWithAlreadyReportedError -> istate,CompletedWithAlreadyReportedError (* drop nextAction on error *) - | EndOfFile -> istate,defaultArg lastResult (Completed None) (* drop nextAction on EOF *) - | CtrlC -> istate,CtrlC (* drop nextAction on CtrlC *) + | _ -> + + let defsA = Seq.takeWhile (isDefHash >> not) defs |> Seq.toList + let defsB = Seq.skipWhile (isDefHash >> not) defs |> Seq.toList + + // If user is debugging their script interactively, inject call + // to Debugger.Break() at the first "breakable" line. + // Update istate so that more Break() calls aren't injected when recursing + let defsA,istate = + if istate.debugBreak then + let preBreak = Seq.takeWhile (isBreakable >> not) defsA |> Seq.toList + let postBreak = Seq.skipWhile (isBreakable >> not) defsA |> Seq.toList + match postBreak with + | h :: _ -> preBreak @ (fsiDynamicCompiler.CreateDebuggerBreak(h.Range) :: postBreak), { istate with debugBreak = false } + | _ -> defsA, istate + else defsA,istate + + // When the last declaration has a shape of DoExp (i.e., non-binding), + // transform it to a shape of "let it = ", so we can refer it. + let defsA = + if not (isNil defsB) then defsA else + match defsA with + | [] -> defsA + | [_] -> defsA + | _ -> + match List.rev defsA with + | SynModuleDecl.Expr(expr, _) :: rest -> (rest |> List.rev) @ (fsiDynamicCompiler.BuildItBinding expr) + | _ -> defsA + + let group = InteractionGroup.Definitions(defsA,m) + let others = ParsedScriptInteraction.Definitions(defsB,m) + Some group,Some others, istate + + match group with + | None -> + istate, Completed lastResult + | Some group -> + let status = ExecuteInteractionGroup (ctok, istate, group, diagnosticsLogger) + ProcessStepStatus status lastResult (fun lastResult istate -> + ExecuteParsedInteractionInGroups (ctok, istate, others, diagnosticsLogger, lastResult, cancellationToken)) /// Execute a single parsed interaction which may contain multiple items to be executed /// independently - let executeParsedInteractions (ctok, tcConfig, istate, action, diagnosticsLogger: DiagnosticsLogger, lastResult: FsiInteractionStepStatus option, cancellationToken: CancellationToken) = - let istate, completed = execParsedInteractions (ctok, tcConfig, istate, action, diagnosticsLogger, lastResult, cancellationToken) - match completed with - | Completed _ -> - let istate = fsiDynamicCompiler.CommitDependencyManagerText(ctok, istate, lexResourceManager, diagnosticsLogger) - istate, completed - | _ -> istate, completed + let ExecuteParsedInteraction (ctok, istate, synInteraction, diagnosticsLogger: DiagnosticsLogger, lastResult: FsiValue option, cancellationToken: CancellationToken) = + let status = ExecuteParsedInteractionInGroups (ctok, istate, synInteraction, diagnosticsLogger, lastResult, cancellationToken) + ProcessStepStatus status lastResult (fun lastResult istate -> + let rec loop istate = + if fsiDynamicCompiler.HasDelayedDependencyManagerText then + let istate = fsiDynamicCompiler.ProcessDelayedDependencyManagerText(ctok, istate, lexResourceManager, diagnosticsLogger) + loop istate + elif fsiDynamicCompiler.HasDelayedReferences then + let istate = fsiDynamicCompiler.ProcessDelayedReferences (ctok, istate) + loop istate + else + istate, Completed lastResult + loop istate) /// Execute a single parsed interaction on the parser/execute thread. let mainThreadProcessAction ctok action istate = @@ -2880,10 +2984,9 @@ type FsiInteractionProcessor let mutable result = Unchecked.defaultof<'a * FsiInteractionStepStatus> fsiInterruptController.ControlledExecution().Run( fun () -> - let tcConfig = TcConfig.Create(tcConfigB,validate=false) if progress then fprintfn fsiConsoleOutput.Out "In mainThreadProcessAction..." fsiInterruptController.InterruptAllowed <- InterruptCanRaiseException; - let res = action ctok tcConfig istate + let res = action ctok istate fsiInterruptController.ClearInterruptRequest() fsiInterruptController.InterruptAllowed <- InterruptIgnored result <- res) @@ -2908,17 +3011,17 @@ type FsiInteractionProcessor stopProcessingRecovery e range0; istate, CompletedWithReportedError e - let mainThreadProcessParsedInteractions ctok diagnosticsLogger (action, istate) cancellationToken = - istate |> mainThreadProcessAction ctok (fun ctok tcConfig istate -> - executeParsedInteractions (ctok, tcConfig, istate, action, diagnosticsLogger, None, cancellationToken)) + let ExecuteParsedInteractionOnMainThread (ctok, diagnosticsLogger, synInteraction, istate, cancellationToken) = + istate |> mainThreadProcessAction ctok (fun ctok istate -> + ExecuteParsedInteraction (ctok, istate, synInteraction, diagnosticsLogger, None, cancellationToken)) - let parseExpression (tokenizer:LexFilter.LexFilter) = + let ParseExpression (tokenizer:LexFilter.LexFilter) = reusingLexbufForParsing tokenizer.LexBuffer (fun () -> Parser.typedSequentialExprEOF (fun _ -> tokenizer.GetToken()) tokenizer.LexBuffer) - let mainThreadProcessParsedExpression ctok diagnosticsLogger (expr, istate) = + let ExecuteParsedExpressionOnMainThread (ctok, diagnosticsLogger, expr, istate) = istate |> InteractiveCatch diagnosticsLogger (fun istate -> - istate |> mainThreadProcessAction ctok (fun ctok _tcConfig istate -> + istate |> mainThreadProcessAction ctok (fun ctok istate -> fsiDynamicCompiler.EvalParsedExpression(ctok, diagnosticsLogger, istate, expr) )) let commitResult (istate, result) = @@ -2944,7 +3047,7 @@ type FsiInteractionProcessor /// During processing of startup scripts, this runs on the main thread. /// /// This is blocking: it reads until one chunk of input have been received, unless IsPastEndOfStream is true - member _.ParseAndExecOneSetOfInteractionsFromLexbuf (runCodeOnMainThread, istate:FsiDynamicCompilerState, tokenizer:LexFilter.LexFilter, diagnosticsLogger, ?cancellationToken: CancellationToken) = + member _.ParseAndExecuteInteractionFromLexbuf (runCodeOnMainThread, istate:FsiDynamicCompilerState, tokenizer:LexFilter.LexFilter, diagnosticsLogger, ?cancellationToken: CancellationToken) = let cancellationToken = defaultArg cancellationToken CancellationToken.None if tokenizer.LexBuffer.IsPastEndOfStream then let stepStatus = @@ -2957,21 +3060,21 @@ type FsiInteractionProcessor else - fsiConsolePrompt.Print(); + fsiConsolePrompt.Print() istate |> InteractiveCatch diagnosticsLogger (fun istate -> - if progress then fprintfn fsiConsoleOutput.Out "entering ParseInteraction..."; + if progress then fprintfn fsiConsoleOutput.Out "entering ParseInteraction..." // Parse the interaction. When FSI.EXE is waiting for input from the console the // parser thread is blocked somewhere deep this call. - let action = ParseInteraction tokenizer + let action = ParseInteraction tokenizer - if progress then fprintfn fsiConsoleOutput.Out "returned from ParseInteraction...calling runCodeOnMainThread..."; + if progress then fprintfn fsiConsoleOutput.Out "returned from ParseInteraction...calling runCodeOnMainThread..." // After we've unblocked and got something to run we switch // over to the run-thread (e.g. the GUI thread) - let res = istate |> runCodeOnMainThread (fun ctok istate -> mainThreadProcessParsedInteractions ctok diagnosticsLogger (action, istate) cancellationToken) + let res = istate |> runCodeOnMainThread (fun ctok istate -> ExecuteParsedInteractionOnMainThread (ctok, diagnosticsLogger, action, istate, cancellationToken)) - if progress then fprintfn fsiConsoleOutput.Out "Just called runCodeOnMainThread, res = %O..." res; + if progress then fprintfn fsiConsoleOutput.Out "Just called runCodeOnMainThread, res = %O..." res res) member _.CurrentState = currState @@ -2984,42 +3087,30 @@ type FsiInteractionProcessor // During the processing of the file, further filenames are // resolved relative to the home directory of the loaded file. WithImplicitHome (tcConfigB, directoryName sourceFile) (fun () -> - // An included script file may contain maybe several interaction blocks. - // We repeatedly parse and process these, until an error occurs. - - use fileStream = FileSystem.OpenFileForReadShim(sourceFile) - use reader = fileStream.GetReader(tcConfigB.inputCodePage, false) - - let tokenizer = fsiStdinLexerProvider.CreateIncludedScriptLexer (sourceFile, reader, diagnosticsLogger) - let rec run istate = - let istate,cont = processor.ParseAndExecOneSetOfInteractionsFromLexbuf ((fun f istate -> f ctok istate), istate, tokenizer, diagnosticsLogger) - match cont with Completed _ -> run istate | _ -> istate,cont + // An included script file may parse several interaction blocks. + // We repeatedly parse and process these, until an error occurs. + use fileStream = FileSystem.OpenFileForReadShim(sourceFile) + use reader = fileStream.GetReader(tcConfigB.inputCodePage, false) - let istate,cont = run istate + let tokenizer = fsiStdinLexerProvider.CreateIncludedScriptLexer (sourceFile, reader, diagnosticsLogger) - match cont with - | Completed _ -> failwith "EvalIncludedScript: Completed expected to have relooped" - | CompletedWithAlreadyReportedError -> istate,CompletedWithAlreadyReportedError - | CompletedWithReportedError e -> istate,CompletedWithReportedError e - | EndOfFile -> istate,Completed None// here file-EOF is normal, continue required - | CtrlC -> istate,CtrlC - ) + let rec run istate = + let status = processor.ParseAndExecuteInteractionFromLexbuf ((fun f istate -> f ctok istate), istate, tokenizer, diagnosticsLogger) + ProcessStepStatus status None (fun _ istate -> + run istate) + run istate + ) /// Load the source files, one by one. Called on the main thread. member processor.EvalIncludedScripts (ctok, istate, sourceFiles, diagnosticsLogger) = - match sourceFiles with - | [] -> istate + match sourceFiles with + | [] -> istate, Completed None | sourceFile :: moreSourceFiles -> // Catch errors on a per-file basis, so results/bindings from pre-error files can be kept. - let istate,cont = InteractiveCatch diagnosticsLogger (fun istate -> processor.EvalIncludedScript (ctok, istate, sourceFile, rangeStdin0, diagnosticsLogger)) istate - match cont with - | Completed _ -> processor.EvalIncludedScripts (ctok, istate, moreSourceFiles, diagnosticsLogger) - | CompletedWithAlreadyReportedError -> istate // do not process any more files - | CompletedWithReportedError _ -> istate // do not process any more files - | CtrlC -> istate // do not process any more files - | EndOfFile -> assert false; istate // This is unexpected. EndOfFile is replaced by Completed in the called function - + let status = InteractiveCatch diagnosticsLogger (fun istate -> processor.EvalIncludedScript (ctok, istate, sourceFile, rangeStdin0, diagnosticsLogger)) istate + ProcessStepStatus status None (fun _ istate -> + processor.EvalIncludedScripts (ctok, istate, moreSourceFiles, diagnosticsLogger)) member processor.LoadInitialFiles (ctok, diagnosticsLogger) = /// Consume initial source files in chunks of scripts or non-scripts @@ -3029,11 +3120,11 @@ type FsiInteractionProcessor | (_,isScript1) :: _ -> let sourceFiles,rest = List.takeUntil (fun (_,isScript2) -> isScript1 <> isScript2) sourceFiles let sourceFiles = List.map fst sourceFiles - let istate = + let istate, _ = if isScript1 then processor.EvalIncludedScripts (ctok, istate, sourceFiles, diagnosticsLogger) else - istate |> InteractiveCatch diagnosticsLogger (fun istate -> fsiDynamicCompiler.EvalSourceFiles(ctok, istate, rangeStdin0, sourceFiles, lexResourceManager, diagnosticsLogger), Completed None) |> fst + istate |> InteractiveCatch diagnosticsLogger (fun istate -> fsiDynamicCompiler.EvalSourceFiles(ctok, istate, rangeStdin0, sourceFiles, lexResourceManager, diagnosticsLogger), Completed None) consume istate rest setCurrState (consume currState fsiOptions.SourceFiles) @@ -3056,7 +3147,7 @@ type FsiInteractionProcessor currState |> InteractiveCatch diagnosticsLogger (fun istate -> let expr = ParseInteraction tokenizer - mainThreadProcessParsedInteractions ctok diagnosticsLogger (expr, istate) cancellationToken) + ExecuteParsedInteractionOnMainThread (ctok, diagnosticsLogger, expr, istate, cancellationToken)) |> commitResult member this.EvalScript (ctok, scriptPath, diagnosticsLogger) = @@ -3072,11 +3163,11 @@ type FsiInteractionProcessor let tokenizer = fsiStdinLexerProvider.CreateBufferLexer(scriptFileName, lexbuf, diagnosticsLogger) currState |> InteractiveCatch diagnosticsLogger (fun istate -> - let expr = parseExpression tokenizer + let expr = ParseExpression tokenizer let m = expr.Range // Make this into "(); expr" to suppress generalization and compilation-as-function let exprWithSeq = SynExpr.Sequential (DebugPointAtSequential.SuppressExpr, true, SynExpr.Const (SynConst.Unit,m.StartRange), expr, m) - mainThreadProcessParsedExpression ctok diagnosticsLogger (exprWithSeq, istate)) + ExecuteParsedExpressionOnMainThread (ctok, diagnosticsLogger, exprWithSeq, istate)) |> commitResult member _.AddBoundValue(ctok, diagnosticsLogger, name, value: obj) = @@ -3118,12 +3209,12 @@ type FsiInteractionProcessor // Keep going until EndOfFile on the inReader or console let rec loop currTokenizer = - let istateNew,contNew = - processor.ParseAndExecOneSetOfInteractionsFromLexbuf (runCodeOnMainThread, currState, currTokenizer, diagnosticsLogger) + let istateNew, cont = + processor.ParseAndExecuteInteractionFromLexbuf (runCodeOnMainThread, currState, currTokenizer, diagnosticsLogger) setCurrState istateNew - match contNew with + match cont with | EndOfFile -> () | CtrlC -> loop (fsiStdinLexerProvider.CreateStdinLexer(diagnosticsLogger)) // After each interrupt, restart to a brand new tokenizer | CompletedWithAlreadyReportedError @@ -3132,7 +3223,6 @@ type FsiInteractionProcessor loop initialTokenizer - if progress then fprintfn fsiConsoleOutput.Out "- READER: Exiting stdinReaderThread"; with e -> stopProcessingRecovery e range0; @@ -3162,8 +3252,8 @@ type FsiInteractionProcessor let nenv = tcState.TcEnvFromImpls.NameEnv let nItems = ResolvePartialLongIdent ncenv nenv (ConstraintSolver.IsApplicableMethApprox istate.tcGlobals amap rangeStdin0) rangeStdin0 ad lid false - let names = nItems |> List.map (fun d -> d.DisplayName) - let names = names |> List.filter (fun name -> name.StartsWithOrdinal(stem)) + let names = nItems |> List.map (fun d -> d.DisplayName) + let names = names |> List.filter (fun name -> name.StartsWithOrdinal(stem)) names member _.ParseAndCheckInteraction (legacyReferenceResolver, istate, text:string) = @@ -3172,7 +3262,6 @@ type FsiInteractionProcessor let fsiInteractiveChecker = FsiInteractiveChecker(legacyReferenceResolver, tcConfig, istate.tcGlobals, istate.tcImports, istate.tcState) fsiInteractiveChecker.ParseAndCheckInteraction(SourceText.ofString text) - //---------------------------------------------------------------------------- // Server mode: //---------------------------------------------------------------------------- diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index 9412e8486a..7ef394a67f 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -1651,10 +1651,7 @@ type ParsedSigFileFragment = trivia: SynModuleOrNamespaceSigTrivia [] -type ParsedScriptInteraction = - | Definitions of defns: SynModuleDecl list * range: range - - | HashDirective of hashDirective: ParsedHashDirective * range: range +type ParsedScriptInteraction = Definitions of defns: SynModuleDecl list * range: range [] type ParsedImplFile = ParsedImplFile of hashDirectives: ParsedHashDirective list * fragments: ParsedImplFileFragment list diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index 1dfd44d2c0..8d977a4c02 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -1842,10 +1842,7 @@ type ParsedSigFileFragment = /// Represents a parsed syntax tree for an F# Interactive interaction [] -type ParsedScriptInteraction = - | Definitions of defns: SynModuleDecl list * range: range - - | HashDirective of hashDirective: ParsedHashDirective * range: range +type ParsedScriptInteraction = Definitions of defns: SynModuleDecl list * range: range /// Represents a parsed implementation file made up of fragments [] diff --git a/src/Compiler/TypedTree/TypeProviders.fs b/src/Compiler/TypedTree/TypeProviders.fs index c0b48c2258..662081a1f4 100644 --- a/src/Compiler/TypedTree/TypeProviders.fs +++ b/src/Compiler/TypedTree/TypeProviders.fs @@ -34,7 +34,7 @@ type ResolutionEnvironment = { ResolutionFolder: string OutputFile: string option ShowResolutionMessages: bool - ReferencedAssemblies: string[] + GetReferencedAssemblies: unit -> string[] TemporaryFolder: string } /// Load a the design-time part of a type-provider into the host process, and look for types @@ -118,19 +118,32 @@ let CreateTypeProvider ( let e = StripException (StripException err) raise (TypeProviderError(FSComp.SR.etTypeProviderConstructorException(e.Message), typeProviderImplementationType.FullName, m)) + let getReferencedAssemblies () = + resolutionEnvironment.GetReferencedAssemblies() |> Array.distinct + if typeProviderImplementationType.GetConstructor([| typeof |]) <> null then // Create the TypeProviderConfig to pass to the type provider constructor let e = - TypeProviderConfig(systemRuntimeContainsType, +#if FSHARPCORE_USE_PACKAGE + TypeProviderConfig(systemRuntimeContainsType, + ReferencedAssemblies=getReferencedAssemblies(), ResolutionFolder=resolutionEnvironment.ResolutionFolder, RuntimeAssembly=runtimeAssemblyPath, - ReferencedAssemblies=Array.copy resolutionEnvironment.ReferencedAssemblies, TemporaryFolder=resolutionEnvironment.TemporaryFolder, IsInvalidationSupported=isInvalidationSupported, IsHostedExecution= isInteractive, SystemRuntimeAssemblyVersion = systemRuntimeAssemblyVersion) - +#else + TypeProviderConfig(systemRuntimeContainsType, + getReferencedAssemblies, + ResolutionFolder=resolutionEnvironment.ResolutionFolder, + RuntimeAssembly=runtimeAssemblyPath, + TemporaryFolder=resolutionEnvironment.TemporaryFolder, + IsInvalidationSupported=isInvalidationSupported, + IsHostedExecution= isInteractive, + SystemRuntimeAssemblyVersion = systemRuntimeAssemblyVersion) +#endif protect (fun () -> Activator.CreateInstance(typeProviderImplementationType, [| box e|]) :?> ITypeProvider ) elif typeProviderImplementationType.GetConstructor [| |] <> null then diff --git a/src/Compiler/TypedTree/TypeProviders.fsi b/src/Compiler/TypedTree/TypeProviders.fsi index 5d014938ea..b1e3ccaf85 100755 --- a/src/Compiler/TypedTree/TypeProviders.fsi +++ b/src/Compiler/TypedTree/TypeProviders.fsi @@ -37,7 +37,7 @@ type ResolutionEnvironment = ShowResolutionMessages: bool /// All referenced assemblies, including the type provider itself, and possibly other type providers. - ReferencedAssemblies: string[] + GetReferencedAssemblies: unit -> string[] /// The folder for temporary files TemporaryFolder: string diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index 49cef8a36a..fcb2a84c35 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -10,7 +10,7 @@ open System.IO open System.Threading open System.Threading.Tasks open System.Runtime.CompilerServices -#if !USE_SHIPPED_FSCORE +#if !FSHARPCORE_USE_PACKAGE open FSharp.Core.CompilerServices.StateMachineHelpers #endif @@ -931,7 +931,7 @@ type CancellableBuilder() = member inline _.Bind(comp, [] k) = Cancellable(fun ct -> -#if !USE_SHIPPED_FSCORE +#if !FSHARPCORE_USE_PACKAGE __debugPoint "" #endif @@ -941,7 +941,7 @@ type CancellableBuilder() = member inline _.BindReturn(comp, [] k) = Cancellable(fun ct -> -#if !USE_SHIPPED_FSCORE +#if !FSHARPCORE_USE_PACKAGE __debugPoint "" #endif @@ -951,7 +951,7 @@ type CancellableBuilder() = member inline _.Combine(comp1, comp2) = Cancellable(fun ct -> -#if !USE_SHIPPED_FSCORE +#if !FSHARPCORE_USE_PACKAGE __debugPoint "" #endif @@ -961,7 +961,7 @@ type CancellableBuilder() = member inline _.TryWith(comp, [] handler) = Cancellable(fun ct -> -#if !USE_SHIPPED_FSCORE +#if !FSHARPCORE_USE_PACKAGE __debugPoint "" #endif @@ -982,7 +982,7 @@ type CancellableBuilder() = member inline _.Using(resource, [] comp) = Cancellable(fun ct -> -#if !USE_SHIPPED_FSCORE +#if !FSHARPCORE_USE_PACKAGE __debugPoint "" #endif let body = comp resource @@ -1006,7 +1006,7 @@ type CancellableBuilder() = member inline _.TryFinally(comp, [] compensation) = Cancellable(fun ct -> -#if !USE_SHIPPED_FSCORE +#if !FSHARPCORE_USE_PACKAGE __debugPoint "" #endif @@ -1396,7 +1396,7 @@ module MapAutoOpens = static member Empty: Map<'Key, 'Value> = Map.empty -#if USE_SHIPPED_FSCORE +#if FSHARPCORE_USE_PACKAGE member x.Values = [ for KeyValue (_, v) in x -> v ] #endif diff --git a/src/Compiler/Utilities/illib.fsi b/src/Compiler/Utilities/illib.fsi index 1be82c8489..40f8c8f816 100644 --- a/src/Compiler/Utilities/illib.fsi +++ b/src/Compiler/Utilities/illib.fsi @@ -592,7 +592,7 @@ module internal MapAutoOpens = static member Empty: Map<'Key, 'Value> when 'Key: comparison -#if USE_SHIPPED_FSCORE +#if FSHARPCORE_USE_PACKAGE member Values: 'Value list #endif diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index b732754d7f..119dd6ae47 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -606,7 +606,7 @@ interactiveExpr: { match $2 with | Some vis -> errorR(Error(FSComp.SR.parsUnexpectedVisibilityDeclaration(vis.ToString()), rhs parseState 3)) | _ -> () - let attrDecls = if not (isNil $1) then [ SynModuleDecl.Attributes ($1, rangeOfNonNilAttrs $1) ] else [] in + let attrDecls = if not (isNil $1) then [ SynModuleDecl.Attributes ($1, rangeOfNonNilAttrs $1) ] else [] attrDecls @ [ mkSynExprDecl $3 ] } /* A #directive interaction in F# Interactive */ @@ -614,7 +614,6 @@ interactiveHash: | hashDirective { [SynModuleDecl.HashDirective($1, rhs parseState 1)] } - /* One or more separators between interactions in F# Interactive */ interactiveSeparators: | interactiveSeparator { } diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 04cb5e2725..1d56df844c 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -1317,11 +1317,6 @@ Sestavení {0} se nedalo přeložit. - - Could not resolve assembly '{0}' required by '{1}' - Sestavení {0} požadované souborem {1} se nedalo přeložit. - - Error opening binary file '{0}': {1} Chyba při otevírání binárního souboru {0}: {1} diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index c7f65de13a..0756782570 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -1317,11 +1317,6 @@ Assembly "{0}" konnte nicht aufgelöst werden. - - Could not resolve assembly '{0}' required by '{1}' - Die für "{1}" erforderliche Assembly "{0}" konnte nicht aufgelöst werden. - - Error opening binary file '{0}': {1} Fehler beim Öffnen der Binärdatei "{0}": {1} diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index c76f988d7a..b627eaf231 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -1317,11 +1317,6 @@ No se pudo resolver el ensamblado '{0}'. - - Could not resolve assembly '{0}' required by '{1}' - No se pudo resolver el ensamblado '{0}' requerido por '{1}'. - - Error opening binary file '{0}': {1} Error al abrir el archivo binario '{0}': {1}. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index a89ad51030..8ff78e1d34 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -1317,11 +1317,6 @@ Impossible de résoudre l'assembly '{0}' - - Could not resolve assembly '{0}' required by '{1}' - Impossible de résoudre l'assembly '{0}' requis par '{1}' - - Error opening binary file '{0}': {1} Erreur lors de l'ouverture du fichier binaire '{0}' : {1} diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index a4044cee24..4f1344f084 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -1317,11 +1317,6 @@ Non è stato possibile risolvere l'assembly '{0}' - - Could not resolve assembly '{0}' required by '{1}' - Non è stato possibile risolvere l'assembly '{0}' richiesto da '{1}' - - Error opening binary file '{0}': {1} Errore durante l'apertura del file binario '{0}': {1} diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 06c51c429d..3be4cc8799 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -1317,11 +1317,6 @@ アセンブリ '{0}' を解決できませんでした - - Could not resolve assembly '{0}' required by '{1}' - {1}' に必要なアセンブリ '{0}' を解決できませんでした - - Error opening binary file '{0}': {1} バイナリ ファイル '{0}' を開くときにエラーが発生しました: {1} diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index f6cfde3fd9..728c94688d 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -1317,11 +1317,6 @@ '{0}' 어셈블리를 확인할 수 없습니다. - - Could not resolve assembly '{0}' required by '{1}' - {1}'에 필요한 '{0}' 어셈블리를 확인할 수 없습니다. - - Error opening binary file '{0}': {1} 이진 파일 '{0}'을(를) 여는 동안 오류가 발생했습니다. {1} diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 95a8895c10..284aef3e01 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -1317,11 +1317,6 @@ Nie można rozpoznać zestawu „{0}” - - Could not resolve assembly '{0}' required by '{1}' - Nie można rozpoznać zestawu „{0}” wymaganego przez „{1}” - - Error opening binary file '{0}': {1} Błąd podczas otwierania pliku binarnego „{0}”: {1} diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index f8e182c61d..a5b2b95436 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -1317,11 +1317,6 @@ Não foi possível resolver o assembly '{0}' - - Could not resolve assembly '{0}' required by '{1}' - Não foi possível resolver o assembly '{0}' requerido por '{1}' - - Error opening binary file '{0}': {1} Erro ao abrir o arquivo binário '{0}': {1} diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 6041cda9ec..545decc436 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -1317,11 +1317,6 @@ Не удалось разрешить сборку "{0}". - - Could not resolve assembly '{0}' required by '{1}' - Не удалось разрешить сборку "{0}", необходимую для "{1}" - - Error opening binary file '{0}': {1} Ошибка при открытии двоичного файла "{0}": {1} diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index d9738db5a5..1c0cfc9042 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -1317,11 +1317,6 @@ '{0}' bütünleştirilmiş kodu çözümlenemedi - - Could not resolve assembly '{0}' required by '{1}' - {1}' tarafından istenen '{0}' bütünleştirilmiş kodu çözümlenemedi - - Error opening binary file '{0}': {1} {0}': {1} ikili dosyasını açma işleminde hata diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 0bf4e08015..bf7eeca1f7 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -1317,11 +1317,6 @@ 无法解析程序集“{0}” - - Could not resolve assembly '{0}' required by '{1}' - 无法解析“{1}”所需的程序集“{0}” - - Error opening binary file '{0}': {1} 打开二进制文件“{0}”时出错: {1} diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 24faf41e95..f2d4f429c8 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -1317,11 +1317,6 @@ 無法解析組件 '{0}' - - Could not resolve assembly '{0}' required by '{1}' - 無法解析 '{1}' 所需的組件 '{0}' - - Error opening binary file '{0}': {1} 開啟二進位檔案 '{0}' 時發生錯誤: {1} diff --git a/src/FSharp.Core/fslib-extra-pervasives.fs b/src/FSharp.Core/fslib-extra-pervasives.fs index 90304bd36d..01fd7018b1 100644 --- a/src/FSharp.Core/fslib-extra-pervasives.fs +++ b/src/FSharp.Core/fslib-extra-pervasives.fs @@ -461,7 +461,11 @@ type TypeProviderTypeAttributes = | SuppressRelocate = 0x80000000 | IsErased = 0x40000000 -type TypeProviderConfig(systemRuntimeContainsType: string -> bool) = +type TypeProviderConfig + ( + systemRuntimeContainsType: string -> bool, + getReferencedAssembliesOption: (unit -> string array) option + ) = let mutable resolutionFolder: string = null let mutable runtimeAssembly: string = null let mutable referencedAssemblies: string[] = null @@ -470,6 +474,11 @@ type TypeProviderConfig(systemRuntimeContainsType: string -> bool) = let mutable useResolutionFolderAtRuntime: bool = false let mutable systemRuntimeAssemblyVersion: System.Version = null + new(systemRuntimeContainsType) = TypeProviderConfig(systemRuntimeContainsType, getReferencedAssembliesOption = None) + + new(systemRuntimeContainsType, getReferencedAssemblies) = + TypeProviderConfig(systemRuntimeContainsType, getReferencedAssembliesOption = Some getReferencedAssemblies) + member _.ResolutionFolder with get () = resolutionFolder and set v = resolutionFolder <- v @@ -479,8 +488,15 @@ type TypeProviderConfig(systemRuntimeContainsType: string -> bool) = and set v = runtimeAssembly <- v member _.ReferencedAssemblies - with get () = referencedAssemblies - and set v = referencedAssemblies <- v + with get () = + match getReferencedAssembliesOption with + | None -> referencedAssemblies + | Some f -> f () + + and set v = + match getReferencedAssembliesOption with + | None -> referencedAssemblies <- v + | Some _ -> raise (InvalidOperationException()) member _.TemporaryFolder with get () = temporaryFolder diff --git a/src/FSharp.Core/fslib-extra-pervasives.fsi b/src/FSharp.Core/fslib-extra-pervasives.fsi index 29915a1b5b..ea1ec13f76 100644 --- a/src/FSharp.Core/fslib-extra-pervasives.fsi +++ b/src/FSharp.Core/fslib-extra-pervasives.fsi @@ -454,8 +454,13 @@ namespace Microsoft.FSharp.Core.CompilerServices /// If the class that implements ITypeProvider has a constructor that accepts TypeProviderConfig /// then it will be constructed with an instance of TypeProviderConfig. type TypeProviderConfig = + + /// Create a configuration which calls the given function for the corresponding operation. new : systemRuntimeContainsType : (string -> bool) -> TypeProviderConfig + /// Create a configuration which calls the given functions for the corresponding operation. + new : systemRuntimeContainsType : (string -> bool) * getReferencedAssemblies : (unit -> string[]) -> TypeProviderConfig + /// Get the full path to use to resolve relative paths in any file name arguments given to the type provider instance. member ResolutionFolder : string with get,set diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index 1d2367fb0a..9045f24ab2 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -5592,27 +5592,13 @@ FSharp.Compiler.Syntax.ParsedInput: System.String FileName FSharp.Compiler.Syntax.ParsedInput: System.String ToString() FSharp.Compiler.Syntax.ParsedInput: System.String get_FileName() FSharp.Compiler.Syntax.ParsedScriptInteraction -FSharp.Compiler.Syntax.ParsedScriptInteraction+Definitions: FSharp.Compiler.Text.Range get_range() -FSharp.Compiler.Syntax.ParsedScriptInteraction+Definitions: FSharp.Compiler.Text.Range range -FSharp.Compiler.Syntax.ParsedScriptInteraction+Definitions: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleDecl] defns -FSharp.Compiler.Syntax.ParsedScriptInteraction+Definitions: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleDecl] get_defns() -FSharp.Compiler.Syntax.ParsedScriptInteraction+HashDirective: FSharp.Compiler.Syntax.ParsedHashDirective get_hashDirective() -FSharp.Compiler.Syntax.ParsedScriptInteraction+HashDirective: FSharp.Compiler.Syntax.ParsedHashDirective hashDirective -FSharp.Compiler.Syntax.ParsedScriptInteraction+HashDirective: FSharp.Compiler.Text.Range get_range() -FSharp.Compiler.Syntax.ParsedScriptInteraction+HashDirective: FSharp.Compiler.Text.Range range -FSharp.Compiler.Syntax.ParsedScriptInteraction+Tags: Int32 Definitions -FSharp.Compiler.Syntax.ParsedScriptInteraction+Tags: Int32 HashDirective -FSharp.Compiler.Syntax.ParsedScriptInteraction: Boolean IsDefinitions -FSharp.Compiler.Syntax.ParsedScriptInteraction: Boolean IsHashDirective -FSharp.Compiler.Syntax.ParsedScriptInteraction: Boolean get_IsDefinitions() -FSharp.Compiler.Syntax.ParsedScriptInteraction: Boolean get_IsHashDirective() FSharp.Compiler.Syntax.ParsedScriptInteraction: FSharp.Compiler.Syntax.ParsedScriptInteraction NewDefinitions(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleDecl], FSharp.Compiler.Text.Range) -FSharp.Compiler.Syntax.ParsedScriptInteraction: FSharp.Compiler.Syntax.ParsedScriptInteraction NewHashDirective(FSharp.Compiler.Syntax.ParsedHashDirective, FSharp.Compiler.Text.Range) -FSharp.Compiler.Syntax.ParsedScriptInteraction: FSharp.Compiler.Syntax.ParsedScriptInteraction+Definitions -FSharp.Compiler.Syntax.ParsedScriptInteraction: FSharp.Compiler.Syntax.ParsedScriptInteraction+HashDirective -FSharp.Compiler.Syntax.ParsedScriptInteraction: FSharp.Compiler.Syntax.ParsedScriptInteraction+Tags +FSharp.Compiler.Syntax.ParsedScriptInteraction: FSharp.Compiler.Text.Range get_range() +FSharp.Compiler.Syntax.ParsedScriptInteraction: FSharp.Compiler.Text.Range range FSharp.Compiler.Syntax.ParsedScriptInteraction: Int32 Tag FSharp.Compiler.Syntax.ParsedScriptInteraction: Int32 get_Tag() +FSharp.Compiler.Syntax.ParsedScriptInteraction: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleDecl] defns +FSharp.Compiler.Syntax.ParsedScriptInteraction: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleDecl] get_defns() FSharp.Compiler.Syntax.ParsedScriptInteraction: System.String ToString() FSharp.Compiler.Syntax.ParsedSigFile FSharp.Compiler.Syntax.ParsedSigFile: FSharp.Compiler.Syntax.ParsedSigFile NewParsedSigFile(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedSigFileFragment]) diff --git a/tests/FSharp.Core.UnitTests/SurfaceArea.fs b/tests/FSharp.Core.UnitTests/SurfaceArea.fs index 51de2a7a3f..95d9db63ca 100644 --- a/tests/FSharp.Core.UnitTests/SurfaceArea.fs +++ b/tests/FSharp.Core.UnitTests/SurfaceArea.fs @@ -883,6 +883,7 @@ Microsoft.FSharp.Core.CompilerServices.TypeProviderConfig: System.String[] get_R Microsoft.FSharp.Core.CompilerServices.TypeProviderConfig: System.Version SystemRuntimeAssemblyVersion Microsoft.FSharp.Core.CompilerServices.TypeProviderConfig: System.Version get_SystemRuntimeAssemblyVersion() Microsoft.FSharp.Core.CompilerServices.TypeProviderConfig: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[System.String,System.Boolean]) +Microsoft.FSharp.Core.CompilerServices.TypeProviderConfig: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[System.String,System.Boolean], Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.String[]]) Microsoft.FSharp.Core.CompilerServices.TypeProviderConfig: Void set_IsHostedExecution(Boolean) Microsoft.FSharp.Core.CompilerServices.TypeProviderConfig: Void set_IsInvalidationSupported(Boolean) Microsoft.FSharp.Core.CompilerServices.TypeProviderConfig: Void set_ReferencedAssemblies(System.String[]) diff --git a/tests/fsharp/regression/13710/test.fsx b/tests/fsharp/regression/13710/test.fsx new file mode 100644 index 0000000000..e80a3ecd54 --- /dev/null +++ b/tests/fsharp/regression/13710/test.fsx @@ -0,0 +1,17 @@ +// See https://github.com/dotnet/fsharp/issues/13710 +// +// Note FSharp.Data 5.0.1 is split into two packages, where the type providers depend on FSharp.Data.Core +// +// The TypeProviderCOnfig reported to the type providers must contain both FSharp.Data and FSharp.Data.Core. +#r "nuget: FSharp.Data, 5.0.1" + +open FSharp.Data +type Auth = JsonProvider<"""{ "test": 1 }"""> +let auth = Auth.Parse("""{ "test": 1 }""") +printfn $"{auth.Test}" + +// This is a compilation test, not a lot actually happens in the test +do (System.Console.Out.WriteLine "Test Passed"; + System.IO.File.WriteAllText("test.ok", "ok"); + exit 0) + diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index a43f9b08d8..e1ec4ad346 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -2165,6 +2165,9 @@ module RegressionTests = let cfg = testConfig "regression/4715" fsc cfg "%s -o:test.exe --optimize+" cfg.fsc_flags ["date.fs"; "env.fs"; "main.fs"] + [] + let ``multi-package-type-provider-test-FSI`` () = singleTestBuildAndRun "regression/13710" FSI + #if NETCOREAPP [] let ``Large inputs 12322 fsc.dll 64-bit fsc.dll .NET SDK generating optimized code`` () = @@ -3418,29 +3421,29 @@ module GeneratedSignatureTests = [] module OverloadResolution = module ``fsharpqa migrated tests`` = - let [] ``Conformance\Expressions\SyntacticSugar (E_Slices01.fs)`` () = singleNegTest (testConfig "conformance/expressions/syntacticsugar") "E_Slices01" - let [] ``Conformance\Expressions\Type-relatedExpressions (E_RigidTypeAnnotation03.fsx)`` () = singleNegTest (testConfig "conformance/expressions/type-relatedexpressions") "E_RigidTypeAnnotation03" - let [] ``Conformance\Inference (E_OneTypeVariable03.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_OneTypeVariable03" - let [] ``Conformance\Inference (E_OneTypeVariable03rec.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_OneTypeVariable03rec" - let [] ``Conformance\Inference (E_TwoDifferentTypeVariablesGen00.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoDifferentTypeVariablesGen00" - let [] ``Conformance\Inference (E_TwoDifferentTypeVariables01.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoDifferentTypeVariables01" - let [] ``Conformance\Inference (E_TwoDifferentTypeVariables01rec.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoDifferentTypeVariables01rec" - let [] ``Conformance\Inference (E_TwoDifferentTypeVariablesGen00rec.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoDifferentTypeVariablesGen00rec" - let [] ``Conformance\Inference (E_TwoEqualTypeVariables02.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoEqualTypeVariables02" - let [] ``Conformance\Inference (E_TwoEqualYypeVariables02rec.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoEqualYypeVariables02rec" - let [] ``Conformance\Inference (E_LeftToRightOverloadResolution01.fs)`` () = singleNegTest (testConfig "conformance/inference") "E_LeftToRightOverloadResolution01" - let [] ``Conformance\WellFormedness (E_Clashing_Values_in_AbstractClass01.fs)`` () = singleNegTest (testConfig "conformance/wellformedness") "E_Clashing_Values_in_AbstractClass01" - let [] ``Conformance\WellFormedness (E_Clashing_Values_in_AbstractClass03.fs)`` () = singleNegTest (testConfig "conformance/wellformedness") "E_Clashing_Values_in_AbstractClass03" - let [] ``Conformance\WellFormedness (E_Clashing_Values_in_AbstractClass04.fs)`` () = singleNegTest (testConfig "conformance/wellformedness") "E_Clashing_Values_in_AbstractClass04" + let [] ``Conformance\Expressions\SyntacticSugar (E_Slices01_fs)`` () = singleNegTest (testConfig "conformance/expressions/syntacticsugar") "E_Slices01" + let [] ``Conformance\Expressions\Type-relatedExpressions (E_RigidTypeAnnotation03_fsx)`` () = singleNegTest (testConfig "conformance/expressions/type-relatedexpressions") "E_RigidTypeAnnotation03" + let [] ``Conformance\Inference (E_OneTypeVariable03_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_OneTypeVariable03" + let [] ``Conformance\Inference (E_OneTypeVariable03rec_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_OneTypeVariable03rec" + let [] ``Conformance\Inference (E_TwoDifferentTypeVariablesGen00_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoDifferentTypeVariablesGen00" + let [] ``Conformance\Inference (E_TwoDifferentTypeVariables01_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoDifferentTypeVariables01" + let [] ``Conformance\Inference (E_TwoDifferentTypeVariables01rec_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoDifferentTypeVariables01rec" + let [] ``Conformance\Inference (E_TwoDifferentTypeVariablesGen00rec_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoDifferentTypeVariablesGen00rec" + let [] ``Conformance\Inference (E_TwoEqualTypeVariables02_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoEqualTypeVariables02" + let [] ``Conformance\Inference (E_TwoEqualYypeVariables02rec_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_TwoEqualYypeVariables02rec" + let [] ``Conformance\Inference (E_LeftToRightOverloadResolution01_fs)`` () = singleNegTest (testConfig "conformance/inference") "E_LeftToRightOverloadResolution01" + let [] ``Conformance\WellFormedness (E_Clashing_Values_in_AbstractClass01_fs)`` () = singleNegTest (testConfig "conformance/wellformedness") "E_Clashing_Values_in_AbstractClass01" + let [] ``Conformance\WellFormedness (E_Clashing_Values_in_AbstractClass03_fs)`` () = singleNegTest (testConfig "conformance/wellformedness") "E_Clashing_Values_in_AbstractClass03" + let [] ``Conformance\WellFormedness (E_Clashing_Values_in_AbstractClass04_fs)`` () = singleNegTest (testConfig "conformance/wellformedness") "E_Clashing_Values_in_AbstractClass04" // note: this test still exist in fsharpqa to assert the compiler doesn't crash // the part of the code generating a flaky error due to https://github.com/dotnet/fsharp/issues/6725 // is elided here to focus on overload resolution error messages - let [] ``Conformance\LexicalAnalysis\SymbolicOperators (E_LessThanDotOpenParen001.fs)`` () = singleNegTest (testConfig "conformance/lexicalanalysis") "E_LessThanDotOpenParen001" + let [] ``Conformance\LexicalAnalysis\SymbolicOperators (E_LessThanDotOpenParen001_fs)`` () = singleNegTest (testConfig "conformance/lexicalanalysis") "E_LessThanDotOpenParen001" module ``error messages using BCL``= - let [] ``neg_System.Convert.ToString.OverloadList``() = singleNegTest (testConfig "typecheck/overloads") "neg_System.Convert.ToString.OverloadList" - let [] ``neg_System.Threading.Tasks.Task.Run.OverloadList``() = singleNegTest (testConfig "typecheck/overloads") "neg_System.Threading.Tasks.Task.Run.OverloadList" - let [] ``neg_System.Drawing.Graphics.DrawRectangleOverloadList.fsx``() = singleNegTest (testConfig "typecheck/overloads") "neg_System.Drawing.Graphics.DrawRectangleOverloadList" + let [] ``neg_System_Convert_ToString_OverloadList``() = singleNegTest (testConfig "typecheck/overloads") "neg_System.Convert.ToString.OverloadList" + let [] ``neg_System_Threading_Tasks_Task_Run_OverloadList``() = singleNegTest (testConfig "typecheck/overloads") "neg_System.Threading.Tasks.Task.Run.OverloadList" + let [] ``neg_System_Drawing_Graphics_DrawRectangleOverloadList_fsx``() = singleNegTest (testConfig "typecheck/overloads") "neg_System.Drawing.Graphics.DrawRectangleOverloadList" module ``ad hoc code overload error messages``= let [] ``neg_many_many_overloads`` () = singleNegTest (testConfig "typecheck/overloads") "neg_many_many_overloads"