diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index f799ca8c7bc..55ecb1d1d01 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -3,6 +3,7 @@ module FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.IO +open Internal.Utilities.Library #nowarn "49" #nowarn "343" // The type 'ILAssemblyRef' implements 'System.IComparable' explicitly but provides no corresponding override for 'Object.Equals'. @@ -29,16 +30,14 @@ let _ = if logging then dprintn "* warning: Il.logging is on" -let notlazy v = Lazy<_>.CreateFromValue v - /// A little ugly, but the idea is that if a data structure does not /// contain lazy values then we don't add laziness. So if the thing to map /// is already evaluated then immediately apply the function. -let lazyMap f (x: Lazy<_>) = +let lazyMap f (x: InterruptibleLazy<_>) = if x.IsValueCreated then notlazy (f (x.Force())) else - lazy (f (x.Force())) + InterruptibleLazy(fun _ -> f (x.Force())) [] type PrimaryAssembly = @@ -165,7 +164,7 @@ let splitTypeNameRight nm = // -------------------------------------------------------------------- /// This is used to store event, property and field maps. -type LazyOrderedMultiMap<'Key, 'Data when 'Key: equality>(keyf: 'Data -> 'Key, lazyItems: Lazy<'Data list>) = +type LazyOrderedMultiMap<'Key, 'Data when 'Key: equality>(keyf: 'Data -> 'Key, lazyItems: InterruptibleLazy<'Data list>) = let quickMap = lazyItems @@ -1822,7 +1821,7 @@ type ILMethodVirtualInfo = [] type MethodBody = - | IL of Lazy + | IL of InterruptibleLazy | PInvoke of Lazy (* platform invoke to native *) | Abstract | Native @@ -1903,7 +1902,7 @@ type ILMethodDef callingConv: ILCallingConv, parameters: ILParameters, ret: ILReturn, - body: Lazy, + body: InterruptibleLazy, isEntryPoint: bool, genericParams: ILGenericParameterDefs, securityDeclsStored: ILSecurityDeclsStored, @@ -1962,7 +1961,7 @@ type ILMethodDef ?callingConv: ILCallingConv, ?parameters: ILParameters, ?ret: ILReturn, - ?body: Lazy, + ?body: InterruptibleLazy, ?securityDecls: ILSecurityDecls, ?isEntryPoint: bool, ?genericParams: ILGenericParameterDefs, @@ -2468,7 +2467,7 @@ type ILMethodImplDef = // Index table by name and arity. type ILMethodImplDefs = - | ILMethodImpls of Lazy + | ILMethodImpls of InterruptibleLazy member x.AsList() = let (ILMethodImpls ltab) = x in Map.foldBack (fun _x y r -> y @ r) (ltab.Force()) [] @@ -2919,7 +2918,7 @@ type ILNestedExportedType = override x.ToString() = "exported type " + x.Name and ILNestedExportedTypes = - | ILNestedExportedTypes of Lazy> + | ILNestedExportedTypes of InterruptibleLazy> member x.AsList() = let (ILNestedExportedTypes ltab) = x in Map.foldBack (fun _x y r -> y :: r) (ltab.Force()) [] @@ -2943,7 +2942,7 @@ and [] ILExportedTypeOrForwarder = override x.ToString() = "exported type " + x.Name and ILExportedTypesAndForwarders = - | ILExportedTypesAndForwarders of Lazy> + | ILExportedTypesAndForwarders of InterruptibleLazy> member x.AsList() = let (ILExportedTypesAndForwarders ltab) = x in Map.foldBack (fun _x y r -> y :: r) (ltab.Force()) [] @@ -3784,7 +3783,7 @@ let mkILMethodBody (initlocals, locals, maxstack, code, tag, imports) : ILMethod let mkMethodBody (zeroinit, locals, maxstack, code, tag, imports) = let ilCode = mkILMethodBody (zeroinit, locals, maxstack, code, tag, imports) - MethodBody.IL(lazy ilCode) + MethodBody.IL(InterruptibleLazy.FromValue ilCode) // -------------------------------------------------------------------- // Make a constructor @@ -4098,7 +4097,7 @@ let mkILExportedTypes l = ILExportedTypesAndForwarders(notlazy (List.foldBack addExportedTypeToTable l Map.empty)) let mkILExportedTypesLazy (l: Lazy<_>) = - ILExportedTypesAndForwarders(lazy (List.foldBack addExportedTypeToTable (l.Force()) Map.empty)) + ILExportedTypesAndForwarders(InterruptibleLazy(fun _ -> List.foldBack addExportedTypeToTable (l.Force()) Map.empty)) let addNestedExportedTypeToTable (y: ILNestedExportedType) tab = Map.add y.Name y tab @@ -4116,7 +4115,7 @@ let mkILNestedExportedTypes l = ILNestedExportedTypes(notlazy (List.foldBack addNestedExportedTypeToTable l Map.empty)) let mkILNestedExportedTypesLazy (l: Lazy<_>) = - ILNestedExportedTypes(lazy (List.foldBack addNestedExportedTypeToTable (l.Force()) Map.empty)) + ILNestedExportedTypes(InterruptibleLazy(fun _ -> List.foldBack addNestedExportedTypeToTable (l.Force()) Map.empty)) let mkILResources l = ILResources l let emptyILResources = ILResources [] @@ -4130,7 +4129,7 @@ let mkILMethodImpls l = ILMethodImpls(notlazy (List.foldBack addMethodImplToTable l Map.empty)) let mkILMethodImplsLazy l = - ILMethodImpls(lazy (List.foldBack addMethodImplToTable (Lazy.force l) Map.empty)) + ILMethodImpls(InterruptibleLazy(fun _ -> List.foldBack addMethodImplToTable (Lazy.force l) Map.empty)) let emptyILMethodImpls = mkILMethodImpls [] diff --git a/src/Compiler/AbstractIL/il.fsi b/src/Compiler/AbstractIL/il.fsi index 37bfd87e4ae..5ddfeb482c1 100644 --- a/src/Compiler/AbstractIL/il.fsi +++ b/src/Compiler/AbstractIL/il.fsi @@ -984,7 +984,7 @@ type internal ILOverridesSpec = [] type MethodBody = - | IL of Lazy + | IL of InterruptibleLazy | PInvoke of Lazy | Abstract | Native @@ -1033,7 +1033,7 @@ type ILMethodDef = callingConv: ILCallingConv * parameters: ILParameters * ret: ILReturn * - body: Lazy * + body: InterruptibleLazy * isEntryPoint: bool * genericParams: ILGenericParameterDefs * securityDeclsStored: ILSecurityDeclsStored * @@ -1049,7 +1049,7 @@ type ILMethodDef = callingConv: ILCallingConv * parameters: ILParameters * ret: ILReturn * - body: Lazy * + body: InterruptibleLazy * isEntryPoint: bool * genericParams: ILGenericParameterDefs * securityDecls: ILSecurityDecls * @@ -1140,7 +1140,7 @@ type ILMethodDef = ?callingConv: ILCallingConv * ?parameters: ILParameters * ?ret: ILReturn * - ?body: Lazy * + ?body: InterruptibleLazy * ?securityDecls: ILSecurityDecls * ?isEntryPoint: bool * ?genericParams: ILGenericParameterDefs * @@ -2075,11 +2075,11 @@ val internal mkILMethodBody: val internal mkMethodBody: bool * ILLocals * int * ILCode * ILDebugPoint option * ILDebugImports option -> MethodBody -val internal methBodyNotAvailable: Lazy +val internal methBodyNotAvailable: InterruptibleLazy -val internal methBodyAbstract: Lazy +val internal methBodyAbstract: InterruptibleLazy -val internal methBodyNative: Lazy +val internal methBodyNative: InterruptibleLazy val internal mkILCtor: ILMemberAccess * ILParameter list * MethodBody -> ILMethodDef @@ -2217,11 +2217,11 @@ val storeILSecurityDecls: ILSecurityDecls -> ILSecurityDeclsStored val internal mkILSecurityDeclsReader: (int32 -> ILSecurityDecl[]) -> ILSecurityDeclsStored val mkILEvents: ILEventDef list -> ILEventDefs -val mkILEventsLazy: Lazy -> ILEventDefs +val mkILEventsLazy: InterruptibleLazy -> ILEventDefs val emptyILEvents: ILEventDefs val mkILProperties: ILPropertyDef list -> ILPropertyDefs -val mkILPropertiesLazy: Lazy -> ILPropertyDefs +val mkILPropertiesLazy: InterruptibleLazy -> ILPropertyDefs val emptyILProperties: ILPropertyDefs val mkILMethods: ILMethodDef list -> ILMethodDefs @@ -2230,7 +2230,7 @@ val mkILMethodsComputed: (unit -> ILMethodDef[]) -> ILMethodDefs val emptyILMethods: ILMethodDefs val mkILFields: ILFieldDef list -> ILFieldDefs -val mkILFieldsLazy: Lazy -> ILFieldDefs +val mkILFieldsLazy: InterruptibleLazy -> ILFieldDefs val emptyILFields: ILFieldDefs val mkILMethodImpls: ILMethodImplDef list -> ILMethodImplDefs diff --git a/src/Compiler/AbstractIL/ilmorph.fs b/src/Compiler/AbstractIL/ilmorph.fs index 5f8ceb6fc4f..6b17847e726 100644 --- a/src/Compiler/AbstractIL/ilmorph.fs +++ b/src/Compiler/AbstractIL/ilmorph.fs @@ -305,7 +305,7 @@ let morphILMethodBody fMethBody (x: MethodBody) = match x with | MethodBody.IL il -> let ilCode = fMethBody il.Value // Eager - MethodBody.IL(lazy ilCode) + MethodBody.IL(InterruptibleLazy.FromValue ilCode) | x -> x let ospec_ty2ty f (OverridesSpec (mref, ty)) = OverridesSpec(mref_ty2ty f mref, f ty) diff --git a/src/Compiler/AbstractIL/ilread.fs b/src/Compiler/AbstractIL/ilread.fs index 10189157adf..171b88c9933 100644 --- a/src/Compiler/AbstractIL/ilread.fs +++ b/src/Compiler/AbstractIL/ilread.fs @@ -1129,7 +1129,7 @@ type ILMetadataReader = mdfile: BinaryFile pectxtCaptured: PEReader option // only set when reading full PE including code etc. for static linking entryPointToken: TableName * int - dataEndPoints: Lazy + dataEndPoints: InterruptibleLazy fileName: string getNumRows: TableName -> int userStringsStreamPhysicalLoc: int32 @@ -1766,7 +1766,7 @@ let readNativeResources (pectxt: PEReader) = ] let getDataEndPointsDelayed (pectxt: PEReader) ctxtH = - lazy + InterruptibleLazy(fun _ -> let (ctxt: ILMetadataReader) = getHole ctxtH let mdv = ctxt.mdfile.GetView() @@ -1826,14 +1826,14 @@ let getDataEndPointsDelayed (pectxt: PEReader) ctxtH = [ ("managed vtable_fixups", pectxt.vtableFixupsAddr) ]) @ methodRVAs))) |> List.distinct - |> List.sort + |> List.sort) let rvaToData (ctxt: ILMetadataReader) (pectxt: PEReader) nm rva = if rva = 0x0 then failwith "rva is zero" let start = pectxt.anyV2P (nm, rva) - let endPoints = (Lazy.force ctxt.dataEndPoints) + let endPoints = ctxt.dataEndPoints.Value let rec look l = match l with @@ -2424,14 +2424,14 @@ and seekReadField ctxt mdv (numTypars, hasLayout) (idx: int) = and seekReadFields (ctxt: ILMetadataReader) (numTypars, hasLayout) fidx1 fidx2 = mkILFieldsLazy ( - lazy + InterruptibleLazy(fun _ -> let mdv = ctxt.mdfile.GetView() [ if fidx1 > 0 then for i = fidx1 to fidx2 - 1 do yield seekReadField ctxt mdv (numTypars, hasLayout) i - ] + ]) ) and seekReadMethods (ctxt: ILMetadataReader) numTypars midx1 midx2 = @@ -3064,7 +3064,7 @@ and seekReadEvent ctxt mdv numTypars idx = (* REVIEW: can substantially reduce numbers of EventMap and PropertyMap reads by first checking if the whole table mdv sorted according to ILTypeDef tokens and then doing a binary chop *) and seekReadEvents (ctxt: ILMetadataReader) numTypars tidx = mkILEventsLazy ( - lazy + InterruptibleLazy(fun _ -> let mdv = ctxt.mdfile.GetView() match @@ -3090,7 +3090,7 @@ and seekReadEvents (ctxt: ILMetadataReader) numTypars tidx = if beginEventIdx > 0 then for i in beginEventIdx .. endEventIdx - 1 do yield seekReadEvent ctxt mdv numTypars i - ] + ]) ) and seekReadProperty ctxt mdv numTypars idx = @@ -3131,7 +3131,7 @@ and seekReadProperty ctxt mdv numTypars idx = and seekReadProperties (ctxt: ILMetadataReader) numTypars tidx = mkILPropertiesLazy ( - lazy + InterruptibleLazy(fun _ -> let mdv = ctxt.mdfile.GetView() match @@ -3157,7 +3157,7 @@ and seekReadProperties (ctxt: ILMetadataReader) numTypars tidx = if beginPropIdx > 0 then for i in beginPropIdx .. endPropIdx - 1 do yield seekReadProperty ctxt mdv numTypars i - ] + ]) ) and customAttrsReader ctxtH tag : ILAttributesStored = @@ -3251,7 +3251,7 @@ and seekReadConstant (ctxt: ILMetadataReader) idx = | _ -> ILFieldInit.Null and seekReadImplMap (ctxt: ILMetadataReader) nm midx = - lazy + InterruptibleLazy(fun _ -> MethodBody.PInvoke( lazy let mdv = ctxt.mdfile.GetView() @@ -3339,7 +3339,7 @@ and seekReadImplMap (ctxt: ILMetadataReader) nm midx = | Some nm2 -> nm2) Where = seekReadModuleRef ctxt mdv scopeIdx } - ) + )) and seekReadTopCode (ctxt: ILMetadataReader) pev mdv numTypars (sz: int) start = let labelsOfRawOffsets = Dictionary<_, _>(sz / 2) @@ -3633,7 +3633,7 @@ and seekReadTopCode (ctxt: ILMetadataReader) pev mdv numTypars (sz: int) start = instrs, rawToLabel, lab2pc and seekReadMethodRVA (pectxt: PEReader) (ctxt: ILMetadataReader) (nm, noinline, aggressiveinline, numTypars) rva = - lazy + InterruptibleLazy(fun _ -> let pev = pectxt.pefile.GetView() let baseRVA = pectxt.anyV2P ("method rva", rva) // ": reading body of method "+nm+" at rva "+string rva+", phys "+string baseRVA @@ -3650,7 +3650,7 @@ and seekReadMethodRVA (pectxt: PEReader) (ctxt: ILMetadataReader) (nm, noinline, else MethodBody.IL( - lazy + InterruptibleLazy(fun _ -> let pev = pectxt.pefile.GetView() let mdv = ctxt.mdfile.GetView() @@ -3824,8 +3824,8 @@ and seekReadMethodRVA (pectxt: PEReader) (ctxt: ILMetadataReader) (nm, noinline, Code = code DebugRange = None DebugImports = None - } - ) + }) + )) and int32AsILVariantType (ctxt: ILMetadataReader) (n: int32) = if List.memAssoc n (Lazy.force ILVariantTypeRevMap) then diff --git a/src/Compiler/AbstractIL/ilx.fs b/src/Compiler/AbstractIL/ilx.fs index 94bfda1db53..b9c930a5029 100644 --- a/src/Compiler/AbstractIL/ilx.fs +++ b/src/Compiler/AbstractIL/ilx.fs @@ -167,7 +167,7 @@ type IlxClosureInfo = { cloStructure: IlxClosureLambdas cloFreeVars: IlxClosureFreeVar[] - cloCode: Lazy + cloCode: InterruptibleLazy cloUseStaticField: bool } diff --git a/src/Compiler/AbstractIL/ilx.fsi b/src/Compiler/AbstractIL/ilx.fsi index a6a008434be..bb4a7344d84 100644 --- a/src/Compiler/AbstractIL/ilx.fsi +++ b/src/Compiler/AbstractIL/ilx.fsi @@ -4,6 +4,7 @@ module internal FSharp.Compiler.AbstractIL.ILX.Types open FSharp.Compiler.AbstractIL.IL +open Internal.Utilities.Library /// Union case field [] @@ -118,7 +119,7 @@ type IlxClosureApps = type IlxClosureInfo = { cloStructure: IlxClosureLambdas cloFreeVars: IlxClosureFreeVar[] - cloCode: Lazy + cloCode: InterruptibleLazy cloUseStaticField: bool } /// Represents a discriminated union type prior to erasure diff --git a/src/Compiler/Checking/import.fs b/src/Compiler/Checking/import.fs index 23edca4fafb..d96286fa745 100644 --- a/src/Compiler/Checking/import.fs +++ b/src/Compiler/Checking/import.fs @@ -512,9 +512,11 @@ let multisetDiscriminateAndMap nodef tipf (items: ('Key list * 'Value) list) = /// Import an IL type definition as a new F# TAST Entity node. let rec ImportILTypeDef amap m scoref (cpath: CompilationPath) enc nm (tdef: ILTypeDef) = let lazyModuleOrNamespaceTypeForNestedTypes = - lazy + InterruptibleLazy(fun _ -> let cpath = cpath.NestedCompPath nm ModuleOrType ImportILTypeDefs amap m scoref cpath (enc@[tdef]) tdef.NestedTypes + ) + // Add the type itself. Construct.NewILTycon (Some cpath) @@ -541,9 +543,9 @@ and ImportILTypeDefList amap m (cpath: CompilationPath) enc items = items |> multisetDiscriminateAndMap (fun n tgs -> - let modty = lazy (ImportILTypeDefList amap m (cpath.NestedCompPath n (Namespace true)) enc tgs) + let modty = InterruptibleLazy(fun _ -> ImportILTypeDefList amap m (cpath.NestedCompPath n (Namespace true)) enc tgs) Construct.NewModuleOrNamespace (Some cpath) taccessPublic (mkSynId m n) XmlDoc.Empty [] (MaybeLazy.Lazy modty)) - (fun (n, info: Lazy<_>) -> + (fun (n, info: InterruptibleLazy<_>) -> let (scoref2, lazyTypeDef: ILPreTypeDef) = info.Force() ImportILTypeDef amap m scoref2 cpath enc n (lazyTypeDef.GetTypeDef())) @@ -574,19 +576,21 @@ let ImportILAssemblyExportedType amap m auxModLoader (scoref: ILScopeRef) (expor [] else let ns, n = splitILTypeName exportedType.Name - let info = - lazy (match + let info = + InterruptibleLazy (fun _ -> + match (try let modul = auxModLoader exportedType.ScopeRef let ptd = mkILPreTypeDefComputed (ns, n, (fun () -> modul.TypeDefs.FindByName exportedType.Name)) Some ptd with :? KeyNotFoundException -> None) - with - | None -> - error(Error(FSComp.SR.impReferenceToDllRequiredByAssembly(exportedType.ScopeRef.QualifiedName, scoref.QualifiedName, exportedType.Name), m)) - | Some preTypeDef -> - scoref, preTypeDef) - + with + | None -> + error(Error(FSComp.SR.impReferenceToDllRequiredByAssembly(exportedType.ScopeRef.QualifiedName, scoref.QualifiedName, exportedType.Name), m)) + | Some preTypeDef -> + scoref, preTypeDef + ) + [ ImportILTypeDefList amap m (CompPath(scoref, [])) [] [(ns, (n, info))] ] /// Import the "exported types" table for multi-module assemblies. diff --git a/src/Compiler/CodeGen/EraseClosures.fs b/src/Compiler/CodeGen/EraseClosures.fs index b53526183b8..694cec1320c 100644 --- a/src/Compiler/CodeGen/EraseClosures.fs +++ b/src/Compiler/CodeGen/EraseClosures.fs @@ -13,8 +13,6 @@ open FSharp.Compiler.Syntax.PrettyNaming // by compiling down to code pointers, classes etc. // -------------------------------------------------------------------- -let notlazy v = Lazy.CreateFromValue v - let rec stripUpTo n test dest x = if n = 0 then ([], x) @@ -425,7 +423,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = let nowCloRef = IlxClosureRef(nowTypeRef, clo.cloStructure, nowFields) let nowCloSpec = mkILFormalCloRef td.GenericParams nowCloRef clo.cloUseStaticField let nowMethods = List.map (convMethodDef (Some nowCloSpec)) (td.Methods.AsList()) - let ilCloCode = Lazy.force clo.cloCode + let ilCloCode = clo.cloCode.Value let cloDebugRange = ilCloCode.DebugRange let cloImports = ilCloCode.DebugImports @@ -433,7 +431,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = // Adjust all the argument and environment accesses let rewriteCodeToAccessArgsFromEnv laterCloSpec (argToFreeVarMap: (int * IlxClosureFreeVar) list) = - let il = Lazy.force clo.cloCode + let il = clo.cloCode.Value let numLocals = il.Locals.Length let rewriteInstrToAccessArgsFromEnv instr = @@ -546,8 +544,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = // CASE 1b. Build a type application. let boxReturnTy = Some nowReturnTy (* box prior to all I_ret *) - let convil = - convILMethodBody (Some nowCloSpec, boxReturnTy) (Lazy.force clo.cloCode) + let convil = convILMethodBody (Some nowCloSpec, boxReturnTy) clo.cloCode.Value let nowApplyMethDef = mkILGenericVirtualMethod ( @@ -684,7 +681,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = let nowEnvParentClass = typ_Func cenv (typesOfILParams nowParams) nowReturnTy let cloTypeDef = - let convil = convILMethodBody (Some nowCloSpec, None) (Lazy.force clo.cloCode) + let convil = convILMethodBody (Some nowCloSpec, None) clo.cloCode.Value let nowApplyMethDef = mkILNonGenericVirtualInstanceMethod ( @@ -739,7 +736,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = let cloCodeR = match td.Extends with | None -> (mkILNonGenericEmptyCtor (cenv.ilg.typ_Object, None, cloImports)).MethodBody - | Some _ -> convILMethodBody (Some nowCloSpec, None) (Lazy.force clo.cloCode) + | Some _ -> convILMethodBody (Some nowCloSpec, None) clo.cloCode.Value let ctorMethodDef = let flds = (mkILCloFldSpecs cenv nowFields) diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 33b39ce7f73..05786bdeab2 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -1160,7 +1160,7 @@ and IlxGenEnv = imports: ILDebugImports option /// All values in scope - valsInScope: ValMap> + valsInScope: ValMap> /// All witnesses in scope and their mapping to storage for the witness value. witnessesInScope: TraitWitnessInfoHashMap @@ -1614,7 +1614,7 @@ let rec AddStorageForNonLocalModuleOrNamespaceRef cenv g cloc acc (modref: Modul let acc = (acc, modul.ModuleOrNamespaceType.AllValsAndMembers) - ||> Seq.fold (fun acc v -> AddStorageForVal g (v, lazy (ComputeStorageForNonLocalVal cenv g cloc modref v)) acc) + ||> Seq.fold (fun acc v -> AddStorageForVal g (v, InterruptibleLazy(fun _ -> ComputeStorageForNonLocalVal cenv g cloc modref v)) acc) acc @@ -1638,7 +1638,8 @@ let AddStorageForExternalCcu cenv g eenv (ccu: CcuThunk) = let eref = ERefNonLocalPreResolved ccu.Contents (mkNonLocalEntityRef ccu [||]) (eenv, ccu.Contents.ModuleOrNamespaceType.AllValsAndMembers) - ||> Seq.fold (fun acc v -> AddStorageForVal g (v, lazy (ComputeStorageForNonLocalVal cenv g cloc eref v)) acc) + ||> Seq.fold (fun acc v -> + AddStorageForVal g (v, InterruptibleLazy(fun _ -> ComputeStorageForNonLocalVal cenv g cloc eref v)) acc) eenv @@ -3082,7 +3083,9 @@ and DelayCodeGenMethodForExpr cenv mgbuf ((_, _, eenv, _, _, _, _) as args) = // Once this is lazily-evaluated later, it should not put things in queue. They would not be picked up by anyone. let newArgs = change3rdOutOf7 args { eenv with delayCodeGen = false } - let lazyMethodBody = lazy (CodeGenMethodForExpr cenv mgbuf newArgs) + let lazyMethodBody = + InterruptibleLazy(fun _ -> CodeGenMethodForExpr cenv mgbuf newArgs) + cenv.delayedGenMethods.Enqueue(fun () -> lazyMethodBody.Force() |> ignore) lazyMethodBody else @@ -5861,7 +5864,7 @@ and GenObjectExprMethod cenv eenvinner (cgbuf: CodeGenBuffer) useMethodImpl tmet GenGenericParams cenv eenvUnderTypars methTyparsOfOverridingMethod, ilParamsOfOverridingMethod, ilReturnOfOverridingMethod, - MethodBody.IL(lazy ilMethodBody) + MethodBody.IL(InterruptibleLazy.FromValue ilMethodBody) ) // fixup attributes to generate a method impl let mdef = if useMethodImpl then fixupMethodImplFlags mdef else mdef @@ -6410,7 +6413,7 @@ and GenSequenceExpr ILMemberAccess.Public, [], mkILReturn ilCloEnumeratorTy, - MethodBody.IL(lazy mbody) + MethodBody.IL(InterruptibleLazy.FromValue mbody) ) |> AddNonUserCompilerGeneratedAttribs g @@ -6418,7 +6421,13 @@ and GenSequenceExpr let ilCode = CodeGenMethodForExpr cenv cgbuf.mgbuf ([], "Close", eenvinner, 1, None, closeExpr, discardAndReturnVoid) - mkILNonGenericVirtualInstanceMethod ("Close", ILMemberAccess.Public, [], mkILReturn ILType.Void, MethodBody.IL(lazy ilCode)) + mkILNonGenericVirtualInstanceMethod ( + "Close", + ILMemberAccess.Public, + [], + mkILReturn ILType.Void, + MethodBody.IL(InterruptibleLazy.FromValue ilCode) + ) let checkCloseMethod = let ilCode = @@ -6429,7 +6438,7 @@ and GenSequenceExpr ILMemberAccess.Public, [], mkILReturn g.ilg.typ_Bool, - MethodBody.IL(lazy ilCode) + MethodBody.IL(InterruptibleLazy.FromValue ilCode) ) let generateNextMethod = @@ -6441,7 +6450,10 @@ and GenSequenceExpr let ilReturn = mkILReturn g.ilg.typ_Int32 let ilCode = - MethodBody.IL(lazy (CodeGenMethodForExpr cenv cgbuf.mgbuf ([], "GenerateNext", eenvinner, 2, None, generateNextExpr, Return))) + MethodBody.IL( + InterruptibleLazy(fun _ -> + CodeGenMethodForExpr cenv cgbuf.mgbuf ([], "GenerateNext", eenvinner, 2, None, generateNextExpr, Return)) + ) mkILNonGenericVirtualInstanceMethod ("GenerateNext", ILMemberAccess.Public, ilParams, ilReturn, ilCode) @@ -6454,7 +6466,7 @@ and GenSequenceExpr ILMemberAccess.Public, [], mkILReturn ilCloSeqElemTy, - MethodBody.IL(lazy ilCode) + MethodBody.IL(InterruptibleLazy.FromValue ilCode) ) |> AddNonUserCompilerGeneratedAttribs g @@ -6656,7 +6668,7 @@ and GenClosureAsLocalTypeFunction cenv (cgbuf: CodeGenBuffer) eenv thisVars expr ilDirectGenericParams, ilDirectWitnessParams, mkILReturn ilCloFormalReturnTy, - MethodBody.IL(lazy ilCloBody) + MethodBody.IL(InterruptibleLazy.FromValue ilCloBody) ) ] @@ -7072,7 +7084,7 @@ and GenDelegateExpr cenv cgbuf eenvouter expr (TObjExprMethod (slotsig, _attribs ILMemberAccess.Assembly, ilDelegeeParams, ilDelegeeRet, - MethodBody.IL(lazy ilMethodBody) + MethodBody.IL(InterruptibleLazy.FromValue ilMethodBody) ) let delegeeCtorMeth = @@ -10202,7 +10214,9 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: Checke seqpt )) - let cctorMethDef = mkILClassCtor (MethodBody.IL(lazy topCode)) + let cctorMethDef = + mkILClassCtor (MethodBody.IL(InterruptibleLazy.FromValue topCode)) + mgbuf.AddMethodDef(initClassTy.TypeRef, cctorMethDef) // Final file, implicit entry point. We generate no .cctor. @@ -10224,7 +10238,7 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: Checke ILMemberAccess.Public, [], mkILReturn ILType.Void, - MethodBody.IL(lazy topCode) + MethodBody.IL(InterruptibleLazy.FromValue topCode) ) mdef.With(isEntryPoint = true, customAttrs = ilAttrs) @@ -10235,7 +10249,9 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: Checke | None -> if doesSomething then // Add the cctor - let cctorMethDef = mkILClassCtor (MethodBody.IL(lazy topCode)) + let cctorMethDef = + mkILClassCtor (MethodBody.IL(InterruptibleLazy.FromValue topCode)) + mgbuf.AddMethodDef(initClassTy.TypeRef, cctorMethDef) // Commit the directed initializations @@ -10453,8 +10469,8 @@ and GenPrintingMethod cenv eenv methName ilThisTy m = [ if not g.useReflectionFreeCodeGen then match (eenv.valsInScope.TryFind g.sprintf_vref.Deref, eenv.valsInScope.TryFind g.new_format_vref.Deref) with - | Some (Lazy (Method (_, _, sprintfMethSpec, _, _, _, _, _, _, _, _, _))), - Some (Lazy (Method (_, _, newFormatMethSpec, _, _, _, _, _, _, _, _, _))) -> + | Some (InterruptibleLazy (Method (_, _, sprintfMethSpec, _, _, _, _, _, _, _, _, _))), + Some (InterruptibleLazy (Method (_, _, newFormatMethSpec, _, _, _, _, _, _, _, _, _))) -> // The type returned by the 'sprintf' call let funcTy = EraseClosures.mkILFuncTy cenv.ilxPubCloEnv ilThisTy g.ilg.typ_String @@ -10937,11 +10953,9 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) = yield ilMethodDef.WithSpecialName if generateDebugDisplayAttribute then - let (|Lazy|) (x: Lazy<_>) = x.Force() - match (eenv.valsInScope.TryFind g.sprintf_vref.Deref, eenv.valsInScope.TryFind g.new_format_vref.Deref) with - | Some (Lazy (Method (_, _, sprintfMethSpec, _, _, _, _, _, _, _, _, _))), - Some (Lazy (Method (_, _, newFormatMethSpec, _, _, _, _, _, _, _, _, _))) -> + | Some (InterruptibleLazy (Method (_, _, sprintfMethSpec, _, _, _, _, _, _, _, _, _))), + Some (InterruptibleLazy (Method (_, _, newFormatMethSpec, _, _, _, _, _, _, _, _, _))) -> // The type returned by the 'sprintf' call let funcTy = EraseClosures.mkILFuncTy cenv.ilxPubCloEnv ilThisTy g.ilg.typ_String // Give the instantiation of the printf format object, i.e. a Format`5 object compatible with StringFormat diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 1d4b85533b7..c5419de36c0 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -337,7 +337,7 @@ type ImportedAssembly = IsProviderGenerated: bool mutable TypeProviders: Tainted list #endif - FSharpOptimizationData: Microsoft.FSharp.Control.Lazy + FSharpOptimizationData: InterruptibleLazy } type AvailableImportedAssembly = @@ -2049,26 +2049,26 @@ and [] TcImports let ccu = CcuThunk.Create(ccuName, ccuData) let optdata = - lazy - (match Map.tryFind ccuName optDatas with - | None -> None - | Some info -> - let data = - GetOptimizationData(fileName, ilScopeRef, ilModule.TryGetILModuleDef(), info) + InterruptibleLazy(fun _ -> + match Map.tryFind ccuName optDatas with + | None -> None + | Some info -> + let data = + GetOptimizationData(fileName, ilScopeRef, ilModule.TryGetILModuleDef(), info) - let fixupThunk () = - data.OptionalFixup(fun nm -> availableToOptionalCcu (tcImports.FindCcu(ctok, m, nm, lookupOnly = false))) + let fixupThunk () = + data.OptionalFixup(fun nm -> availableToOptionalCcu (tcImports.FindCcu(ctok, m, nm, lookupOnly = false))) - // Make a note of all ccuThunks that may still need to be fixed up when other dlls are loaded - tciLock.AcquireLock(fun tcitok -> - RequireTcImportsLock(tcitok, ccuThunks) + // Make a note of all ccuThunks that may still need to be fixed up when other dlls are loaded + tciLock.AcquireLock(fun tcitok -> + RequireTcImportsLock(tcitok, ccuThunks) - for ccuThunk in data.FixupThunks do - if ccuThunk.IsUnresolvedReference then - ccuThunks.Add(ccuThunk, (fun () -> fixupThunk () |> ignore))) - - Some(fixupThunk ())) + for ccuThunk in data.FixupThunks do + if ccuThunk.IsUnresolvedReference then + ccuThunks.Add(ccuThunk, (fun () -> fixupThunk () |> ignore))) + Some(fixupThunk ()) + ) let ccuinfo = { FSharpViewOfMetadata = ccu diff --git a/src/Compiler/Driver/CompilerImports.fsi b/src/Compiler/Driver/CompilerImports.fsi index f9fa17487ae..ac06a25c2dc 100644 --- a/src/Compiler/Driver/CompilerImports.fsi +++ b/src/Compiler/Driver/CompilerImports.fsi @@ -116,7 +116,7 @@ type ImportedAssembly = IsProviderGenerated: bool mutable TypeProviders: Tainted list #endif - FSharpOptimizationData: Lazy } + FSharpOptimizationData: InterruptibleLazy } /// Tables of assembly resolutions [] diff --git a/src/Compiler/Driver/OptimizeInputs.fs b/src/Compiler/Driver/OptimizeInputs.fs index d6da3a6dbe9..85cde3b6c0e 100644 --- a/src/Compiler/Driver/OptimizeInputs.fs +++ b/src/Compiler/Driver/OptimizeInputs.fs @@ -146,7 +146,9 @@ module private ParallelOptimization = FirstLoopRes = { OptEnv = env0 - OptInfo = lazy failwith "This dummy value wrapped in a Lazy was not expected to be evaluated before being replaced." + OptInfo = + InterruptibleLazy(fun _ -> + failwith "This dummy value wrapped in a Lazy was not expected to be evaluated before being replaced.") HidingInfo = SignatureHidingInfo.Empty // A no-op optimizer OptDuringCodeGen = fun _ expr -> expr @@ -265,9 +267,9 @@ let optimizeFilesSequentially optEnv (phases: PhaseInfo[]) implFiles = { OptEnv = optEnvFirstLoop OptInfo = - lazy + InterruptibleLazy(fun _ -> failwith - "This dummy value wrapped in a Lazy was not expected to be evaluated before being replaced." + "This dummy value wrapped in a Lazy was not expected to be evaluated before being replaced.") HidingInfo = hidden // A no-op optimizer OptDuringCodeGen = fun _ expr -> expr diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 8f36813411f..23cc703954b 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -46,13 +46,6 @@ exception ReportedError of exn option with | ReportedError (Some exn) -> msg + " Original message: " + exn.Message + ")" | _ -> msg -[] -let (|RecoverableException|_|) (exn: Exception) = - if exn.IsOperationCancelled then - ValueNone - else - ValueSome exn - let rec findOriginalException err = match err with | ReportedError (Some err) -> err diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index 04507355b9a..e9040da36ed 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -28,8 +28,6 @@ exception WrappedError of exn * range /// when a lazy thunk is re-evaluated. exception ReportedError of exn option -val (|RecoverableException|_|): exn: Exception -> Exception voption - val findOriginalException: err: exn -> exn type Suggestions = (string -> unit) -> unit diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 671e0a15f5c..667fcc0586b 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -1622,7 +1622,13 @@ let internal mkBoundValueTypedImpl tcGlobals m moduleName name ty = let mutable mty = Unchecked.defaultof<_> let entity = - Construct.NewModuleOrNamespace (Some compPath) vis (Ident(moduleName, m)) XmlDoc.Empty [] (MaybeLazy.Lazy(lazy mty)) + Construct.NewModuleOrNamespace + (Some compPath) + vis + (Ident(moduleName, m)) + XmlDoc.Empty + [] + (MaybeLazy.Lazy(InterruptibleLazy(fun _ -> mty))) let v = Construct.NewVal( diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index 6e35a5688a2..7edabc43fba 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -172,7 +172,7 @@ type ModuleInfo = { ValInfos: ValInfos ModuleOrNamespaceInfos: NameMap } -and LazyModuleInfo = Lazy +and LazyModuleInfo = InterruptibleLazy type ImplFileOptimizationInfo = LazyModuleInfo @@ -1393,10 +1393,10 @@ let AbstractLazyModulInfoByHiding isAssemblyBoundary mhi = let AbstractOptimizationInfoToEssentials = let rec abstractModulInfo (ss: ModuleInfo) = - { ModuleOrNamespaceInfos = NameMap.map (Lazy.force >> abstractModulInfo >> notlazy) ss.ModuleOrNamespaceInfos + { ModuleOrNamespaceInfos = NameMap.map (InterruptibleLazy.force >> abstractModulInfo >> notlazy) ss.ModuleOrNamespaceInfos ValInfos = ss.ValInfos.Filter (fun (v, _) -> v.MustInline) } - and abstractLazyModulInfo ss = ss |> Lazy.force |> abstractModulInfo |> notlazy + and abstractLazyModulInfo ss = ss |> InterruptibleLazy.force |> abstractModulInfo |> notlazy abstractLazyModulInfo @@ -1459,7 +1459,7 @@ let AbstractExprInfoByVars (boundVars: Val list, boundTyVars) ivalue = ValMakesNoCriticalTailcalls=v.ValMakesNoCriticalTailcalls } and abstractModulInfo ss = - { ModuleOrNamespaceInfos = ss.ModuleOrNamespaceInfos |> NameMap.map (Lazy.force >> abstractModulInfo >> notlazy) + { ModuleOrNamespaceInfos = ss.ModuleOrNamespaceInfos |> NameMap.map (InterruptibleLazy.force >> abstractModulInfo >> notlazy) ValInfos = ss.ValInfos.Map (fun (vref, e) -> check vref (abstractValInfo e) ) } @@ -1496,7 +1496,7 @@ let RemapOptimizationInfo g tmenv = (vrefR, vinfo)) } and remapLazyModulInfo ss = - ss |> Lazy.force |> remapModulInfo |> notlazy + ss |> InterruptibleLazy.force |> remapModulInfo |> notlazy remapLazyModulInfo diff --git a/src/Compiler/Optimize/Optimizer.fsi b/src/Compiler/Optimize/Optimizer.fsi index cb4f71247e5..aa205b86221 100644 --- a/src/Compiler/Optimize/Optimizer.fsi +++ b/src/Compiler/Optimize/Optimizer.fsi @@ -8,6 +8,7 @@ open FSharp.Compiler.Text open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TypedTreePickle +open Internal.Utilities.Library [] type OptimizationProcessingMode = @@ -61,7 +62,7 @@ type OptimizationSettings = /// Optimization information type ModuleInfo -type LazyModuleInfo = Lazy +type LazyModuleInfo = InterruptibleLazy type ImplFileOptimizationInfo = LazyModuleInfo diff --git a/src/Compiler/TypedTree/TypeProviders.fs b/src/Compiler/TypedTree/TypeProviders.fs index 16c69bbc71d..e16bad8ac94 100644 --- a/src/Compiler/TypedTree/TypeProviders.fs +++ b/src/Compiler/TypedTree/TypeProviders.fs @@ -300,7 +300,7 @@ type ProvidedTypeComparer() = type ProvidedTypeContext = | NoEntries // The dictionaries are safe because the ProvidedType with the ProvidedTypeContext are only accessed one thread at a time during type-checking. - | Entries of ConcurrentDictionary * Lazy> + | Entries of ConcurrentDictionary * InterruptibleLazy> static member Empty = NoEntries @@ -334,9 +334,11 @@ type ProvidedTypeContext = match ctxt with | NoEntries -> NoEntries | Entries(d1, d2) -> - Entries(d1, lazy (let dict = ConcurrentDictionary(ProvidedTypeComparer.Instance) - for KeyValue (st, tcref) in d2.Force() do dict.TryAdd(st, f tcref) |> ignore - dict)) + Entries(d1, InterruptibleLazy(fun _ -> + let dict = ConcurrentDictionary(ProvidedTypeComparer.Instance) + for KeyValue (st, tcref) in d2.Force() do dict.TryAdd(st, f tcref) |> ignore + dict + )) [] type ProvidedType (x: Type, ctxt: ProvidedTypeContext) = diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index b82490c5209..3caccb5597d 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -5878,7 +5878,7 @@ type Construct() = entity_typars= LazyWithContext.NotLazy [] entity_tycon_repr = repr entity_tycon_tcaug=TyconAugmentation.Create() - entity_modul_type = MaybeLazy.Lazy (lazy ModuleOrNamespaceType(Namespace true, QueueList.ofList [], QueueList.ofList [])) + entity_modul_type = MaybeLazy.Lazy(InterruptibleLazy(fun _ -> ModuleOrNamespaceType(Namespace true, QueueList.ofList [], QueueList.ofList []))) // Generated types get internal accessibility entity_pubpath = Some pubpath entity_cpath = Some cpath diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index cc13376b8a6..26630f4fa82 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -3077,7 +3077,7 @@ type GenericParameterStyle = [] type DisplayEnv = { includeStaticParametersInTypeNames: bool - openTopPathsSorted: Lazy + openTopPathsSorted: InterruptibleLazy openTopPathsRaw: string list list shortTypeNames: bool suppressNestedTypes: bool @@ -3107,7 +3107,7 @@ type DisplayEnv = member x.SetOpenPaths paths = { x with - openTopPathsSorted = (lazy (paths |> List.sortWith (fun p1 p2 -> -(compare p1 p2)))) + openTopPathsSorted = (InterruptibleLazy(fun _ -> paths |> List.sortWith (fun p1 p2 -> -(compare p1 p2)))) openTopPathsRaw = paths } @@ -10249,7 +10249,7 @@ let CombineCcuContentFragments l = let xml = XmlDoc.Merge entity1.XmlDoc entity2.XmlDoc { data1 with entity_attribs = entity1.Attribs @ entity2.Attribs - entity_modul_type = MaybeLazy.Lazy (lazy (CombineModuleOrNamespaceTypes path2 entity1.ModuleOrNamespaceType entity2.ModuleOrNamespaceType)) + entity_modul_type = MaybeLazy.Lazy (InterruptibleLazy(fun _ -> CombineModuleOrNamespaceTypes path2 entity1.ModuleOrNamespaceType entity2.ModuleOrNamespaceType)) entity_opt_data = match data1.entity_opt_data with | Some optData -> Some { optData with entity_xmldoc = xml } diff --git a/src/Compiler/TypedTree/TypedTreeOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.fsi index 4bffdcbde51..7cc531b71c7 100755 --- a/src/Compiler/TypedTree/TypedTreeOps.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.fsi @@ -1048,7 +1048,7 @@ type GenericParameterStyle = type DisplayEnv = { includeStaticParametersInTypeNames: bool - openTopPathsSorted: Lazy + openTopPathsSorted: InterruptibleLazy openTopPathsRaw: string list list shortTypeNames: bool suppressNestedTypes: bool diff --git a/src/Compiler/TypedTree/TypedTreePickle.fs b/src/Compiler/TypedTree/TypedTreePickle.fs index 6a25d4cddbb..5750c9012de 100644 --- a/src/Compiler/TypedTree/TypedTreePickle.fs +++ b/src/Compiler/TypedTree/TypedTreePickle.fs @@ -501,7 +501,7 @@ let private p_lazy_impl p v st = st.os.FixupInt32 fixupPos7 ovalsIdx2 let p_lazy p x st = - p_lazy_impl p (Lazy.force x) st + p_lazy_impl p (InterruptibleLazy.force x) st let p_maybe_lazy p (x: MaybeLazy<_>) st = p_lazy_impl p x.Value st @@ -604,7 +604,7 @@ let u_lazy u st = res #else ignore (len, otyconsIdx1, otyconsIdx2, otyparsIdx1, otyparsIdx2, ovalsIdx1, ovalsIdx2) - Lazy.CreateFromValue(u st) + InterruptibleLazy.FromValue(u st) #endif diff --git a/src/Compiler/TypedTree/TypedTreePickle.fsi b/src/Compiler/TypedTree/TypedTreePickle.fsi index 2d6fc2bdc4d..5e0fa9915c3 100644 --- a/src/Compiler/TypedTree/TypedTreePickle.fsi +++ b/src/Compiler/TypedTree/TypedTreePickle.fsi @@ -44,7 +44,7 @@ val internal p_int: int -> WriterState -> unit val internal p_string: string -> WriterState -> unit /// Serialize a lazy value (eagerly) -val internal p_lazy: pickler<'T> -> Lazy<'T> pickler +val internal p_lazy: pickler<'T> -> InterruptibleLazy<'T> pickler /// Serialize a tuple of data val inline internal p_tup2: pickler<'T1> -> pickler<'T2> -> pickler<'T1 * 'T2> @@ -106,7 +106,7 @@ val internal u_int: ReaderState -> int val internal u_string: ReaderState -> string /// Deserialize a lazy value (eagerly) -val internal u_lazy: unpickler<'T> -> unpickler> +val internal u_lazy: unpickler<'T> -> unpickler> /// Deserialize a tuple val inline internal u_tup2: unpickler<'T2> -> unpickler<'T3> -> unpickler<'T2 * 'T3> diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs index aafab9dd59a..b3c65830a67 100644 --- a/src/Compiler/Utilities/Cancellable.fs +++ b/src/Compiler/Utilities/Cancellable.fs @@ -38,15 +38,6 @@ type Cancellable = | [] -> () | token :: _ -> token.ThrowIfCancellationRequested() -[] -module Cancellable = - type Exception with - - member this.IsOperationCancelled = - match this with - | :? OperationCanceledException -> true - | _ -> false - namespace Internal.Utilities.Library open System diff --git a/src/Compiler/Utilities/Cancellable.fsi b/src/Compiler/Utilities/Cancellable.fsi index 76c187fd98e..23515432bdd 100644 --- a/src/Compiler/Utilities/Cancellable.fsi +++ b/src/Compiler/Utilities/Cancellable.fsi @@ -9,12 +9,6 @@ type Cancellable = static member Token: CancellationToken static member CheckAndThrow: unit -> unit -[] -module internal Cancellable = - type Exception with - - member IsOperationCancelled: bool - namespace Internal.Utilities.Library open System diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index 5210e1661aa..27704703fc9 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -11,13 +11,62 @@ open System.Threading open System.Threading.Tasks open System.Runtime.CompilerServices +[] +type InterruptibleLazy<'T> private (value, valueFactory: unit -> 'T) = + let syncObj = obj () + let mutable valueFactory = valueFactory + let mutable value = value + + new(valueFactory: unit -> 'T) = InterruptibleLazy(Unchecked.defaultof<_>, valueFactory) + + member this.IsValueCreated = + match box valueFactory with + | null -> true + | _ -> false + + member this.Value = + match box valueFactory with + | null -> value + | _ -> + + Monitor.Enter(syncObj) + + try + match box valueFactory with + | null -> () + | _ -> + + value <- valueFactory () + valueFactory <- Unchecked.defaultof<_> + finally + Monitor.Exit(syncObj) + + value + + member this.Force() = this.Value + + static member FromValue(value) = + InterruptibleLazy(value, Unchecked.defaultof<_>) + +module InterruptibleLazy = + let force (x: InterruptibleLazy<'T>) = x.Value + [] module internal PervasiveAutoOpens = /// Logical shift right treating int32 as unsigned integer. /// Code that uses this should probably be adjusted to use unsigned integer types. let (>>>&) (x: int32) (n: int32) = int32 (uint32 x >>> n) - let notlazy v = Lazy<_>.CreateFromValue v + let notlazy v = InterruptibleLazy.FromValue v + + let (|InterruptibleLazy|) (l: InterruptibleLazy<_>) = l.Force() + + [] + let (|RecoverableException|_|) (exn: Exception) = + if exn :? OperationCanceledException then + ValueNone + else + ValueSome exn let inline isNil l = List.isEmpty l @@ -1024,7 +1073,7 @@ type LazyWithContext<'T, 'Ctxt> = x.value <- res x.funcOrException <- null res - with exn -> + with RecoverableException exn -> x.funcOrException <- box (LazyWithContextFailure(exn)) reraise () | _ -> failwith "unreachable" diff --git a/src/Compiler/Utilities/illib.fsi b/src/Compiler/Utilities/illib.fsi index 6f39ebf780f..fa2f1416d9c 100644 --- a/src/Compiler/Utilities/illib.fsi +++ b/src/Compiler/Utilities/illib.fsi @@ -7,13 +7,31 @@ open System.Threading open System.Collections.Generic open System.Runtime.CompilerServices +[] +type InterruptibleLazy<'T> = + new: valueFactory: (unit -> 'T) -> InterruptibleLazy<'T> + + member IsValueCreated: bool + + member Value: 'T + member Force: unit -> 'T + + static member FromValue: value: 'T -> InterruptibleLazy<'T> + +module InterruptibleLazy = + val force: InterruptibleLazy<'T> -> 'T + [] module internal PervasiveAutoOpens = /// Logical shift right treating int32 as unsigned integer. /// Code that uses this should probably be adjusted to use unsigned integer types. val (>>>&): x: int32 -> n: int32 -> int32 - val notlazy: v: 'a -> Lazy<'a> + val notlazy: v: 'a -> InterruptibleLazy<'a> + + val (|InterruptibleLazy|): l: InterruptibleLazy<'T> -> 'T + + val (|RecoverableException|_|): exn: Exception -> Exception voption val inline isNil: l: 'a list -> bool diff --git a/src/Compiler/Utilities/lib.fs b/src/Compiler/Utilities/lib.fs index f1e089350e1..04dce4c4aec 100755 --- a/src/Compiler/Utilities/lib.fs +++ b/src/Compiler/Utilities/lib.fs @@ -383,7 +383,7 @@ type Dumper(x:obj) = [] type MaybeLazy<'T> = | Strict of 'T - | Lazy of Lazy<'T> + | Lazy of InterruptibleLazy<'T> member this.Value: 'T = match this with diff --git a/src/Compiler/Utilities/lib.fsi b/src/Compiler/Utilities/lib.fsi index 10ccfd21a21..c7bccd4211d 100644 --- a/src/Compiler/Utilities/lib.fsi +++ b/src/Compiler/Utilities/lib.fsi @@ -250,7 +250,7 @@ val inline tryGetCacheValue: cache: cache<'a> -> NonNullSlot<'a> voption [] type MaybeLazy<'T> = | Strict of 'T - | Lazy of System.Lazy<'T> + | Lazy of InterruptibleLazy<'T> member Force: unit -> 'T member Value: 'T diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index b89a77167de..5a565c9f6a6 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -794,7 +794,7 @@ FSharp.Compiler.AbstractIL.IL+ILMethodDef: System.Reflection.MethodImplAttribute FSharp.Compiler.AbstractIL.IL+ILMethodDef: System.String Name FSharp.Compiler.AbstractIL.IL+ILMethodDef: System.String ToString() FSharp.Compiler.AbstractIL.IL+ILMethodDef: System.String get_Name() -FSharp.Compiler.AbstractIL.IL+ILMethodDef: Void .ctor(System.String, System.Reflection.MethodAttributes, System.Reflection.MethodImplAttributes, ILCallingConv, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILParameter], ILReturn, System.Lazy`1[FSharp.Compiler.AbstractIL.IL+MethodBody], Boolean, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef], ILSecurityDecls, ILAttributes) +FSharp.Compiler.AbstractIL.IL+ILMethodDef: Void .ctor(System.String, System.Reflection.MethodAttributes, System.Reflection.MethodImplAttributes, ILCallingConv, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILParameter], ILReturn, Internal.Utilities.Library.InterruptibleLazy`1[FSharp.Compiler.AbstractIL.IL+MethodBody], Boolean, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef], ILSecurityDecls, ILAttributes) FSharp.Compiler.AbstractIL.IL+ILMethodDefs: ILMethodDef[] AsArray() FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] AsList() FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] FindByName(System.String) @@ -1699,8 +1699,8 @@ FSharp.Compiler.AbstractIL.IL+ILVersionInfo: UInt16 get_Major() FSharp.Compiler.AbstractIL.IL+ILVersionInfo: UInt16 get_Minor() FSharp.Compiler.AbstractIL.IL+ILVersionInfo: UInt16 get_Revision() FSharp.Compiler.AbstractIL.IL+ILVersionInfo: Void .ctor(UInt16, UInt16, UInt16, UInt16) -FSharp.Compiler.AbstractIL.IL+MethodBody+IL: System.Lazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody] Item -FSharp.Compiler.AbstractIL.IL+MethodBody+IL: System.Lazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody] get_Item() +FSharp.Compiler.AbstractIL.IL+MethodBody+IL: Internal.Utilities.Library.InterruptibleLazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody] Item +FSharp.Compiler.AbstractIL.IL+MethodBody+IL: Internal.Utilities.Library.InterruptibleLazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody] get_Item() FSharp.Compiler.AbstractIL.IL+MethodBody+PInvoke: System.Lazy`1[FSharp.Compiler.AbstractIL.IL+PInvokeMethod] Item FSharp.Compiler.AbstractIL.IL+MethodBody+PInvoke: System.Lazy`1[FSharp.Compiler.AbstractIL.IL+PInvokeMethod] get_Item() FSharp.Compiler.AbstractIL.IL+MethodBody+Tags: Int32 Abstract @@ -1730,7 +1730,7 @@ FSharp.Compiler.AbstractIL.IL+MethodBody: Int32 Tag FSharp.Compiler.AbstractIL.IL+MethodBody: Int32 get_Tag() FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody Abstract FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody Native -FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody NewIL(System.Lazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody]) +FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody NewIL(Internal.Utilities.Library.InterruptibleLazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody]) FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody NewPInvoke(System.Lazy`1[FSharp.Compiler.AbstractIL.IL+PInvokeMethod]) FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody NotAvailable FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody get_Abstract() @@ -1842,12 +1842,12 @@ FSharp.Compiler.AbstractIL.IL: ILAttributesStored storeILCustomAttrs(ILAttribute FSharp.Compiler.AbstractIL.IL: ILEventDefs emptyILEvents FSharp.Compiler.AbstractIL.IL: ILEventDefs get_emptyILEvents() FSharp.Compiler.AbstractIL.IL: ILEventDefs mkILEvents(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILEventDef]) -FSharp.Compiler.AbstractIL.IL: ILEventDefs mkILEventsLazy(System.Lazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILEventDef]]) +FSharp.Compiler.AbstractIL.IL: ILEventDefs mkILEventsLazy(Internal.Utilities.Library.InterruptibleLazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILEventDef]]) FSharp.Compiler.AbstractIL.IL: ILExportedTypesAndForwarders mkILExportedTypes(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILExportedTypeOrForwarder]) FSharp.Compiler.AbstractIL.IL: ILFieldDefs emptyILFields FSharp.Compiler.AbstractIL.IL: ILFieldDefs get_emptyILFields() FSharp.Compiler.AbstractIL.IL: ILFieldDefs mkILFields(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILFieldDef]) -FSharp.Compiler.AbstractIL.IL: ILFieldDefs mkILFieldsLazy(System.Lazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILFieldDef]]) +FSharp.Compiler.AbstractIL.IL: ILFieldDefs mkILFieldsLazy(Internal.Utilities.Library.InterruptibleLazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILFieldDef]]) FSharp.Compiler.AbstractIL.IL: ILMethodDefs emptyILMethods FSharp.Compiler.AbstractIL.IL: ILMethodDefs get_emptyILMethods() FSharp.Compiler.AbstractIL.IL: ILMethodDefs mkILMethods(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef]) @@ -1862,7 +1862,7 @@ FSharp.Compiler.AbstractIL.IL: ILNestedExportedTypes mkILNestedExportedTypes(Mic FSharp.Compiler.AbstractIL.IL: ILPropertyDefs emptyILProperties FSharp.Compiler.AbstractIL.IL: ILPropertyDefs get_emptyILProperties() FSharp.Compiler.AbstractIL.IL: ILPropertyDefs mkILProperties(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILPropertyDef]) -FSharp.Compiler.AbstractIL.IL: ILPropertyDefs mkILPropertiesLazy(System.Lazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILPropertyDef]]) +FSharp.Compiler.AbstractIL.IL: ILPropertyDefs mkILPropertiesLazy(Internal.Utilities.Library.InterruptibleLazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILPropertyDef]]) FSharp.Compiler.AbstractIL.IL: ILResources emptyILResources FSharp.Compiler.AbstractIL.IL: ILResources get_emptyILResources() FSharp.Compiler.AbstractIL.IL: ILReturn mkILReturn(ILType) @@ -11716,4 +11716,12 @@ FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Ran Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] CreateDictionary(T[]) Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] GetDictionary() Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: T[] GetArray() -Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]]) \ No newline at end of file +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]]) +Internal.Utilities.Library.InterruptibleLazy: T force[T](Internal.Utilities.Library.InterruptibleLazy`1[T]) +Internal.Utilities.Library.InterruptibleLazy`1[T]: Boolean IsValueCreated +Internal.Utilities.Library.InterruptibleLazy`1[T]: Boolean get_IsValueCreated() +Internal.Utilities.Library.InterruptibleLazy`1[T]: Internal.Utilities.Library.InterruptibleLazy`1[T] FromValue(T) +Internal.Utilities.Library.InterruptibleLazy`1[T]: T Force() +Internal.Utilities.Library.InterruptibleLazy`1[T]: T Value +Internal.Utilities.Library.InterruptibleLazy`1[T]: T get_Value() +Internal.Utilities.Library.InterruptibleLazy`1[T]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T]) \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index b89a77167de..5a565c9f6a6 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -794,7 +794,7 @@ FSharp.Compiler.AbstractIL.IL+ILMethodDef: System.Reflection.MethodImplAttribute FSharp.Compiler.AbstractIL.IL+ILMethodDef: System.String Name FSharp.Compiler.AbstractIL.IL+ILMethodDef: System.String ToString() FSharp.Compiler.AbstractIL.IL+ILMethodDef: System.String get_Name() -FSharp.Compiler.AbstractIL.IL+ILMethodDef: Void .ctor(System.String, System.Reflection.MethodAttributes, System.Reflection.MethodImplAttributes, ILCallingConv, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILParameter], ILReturn, System.Lazy`1[FSharp.Compiler.AbstractIL.IL+MethodBody], Boolean, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef], ILSecurityDecls, ILAttributes) +FSharp.Compiler.AbstractIL.IL+ILMethodDef: Void .ctor(System.String, System.Reflection.MethodAttributes, System.Reflection.MethodImplAttributes, ILCallingConv, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILParameter], ILReturn, Internal.Utilities.Library.InterruptibleLazy`1[FSharp.Compiler.AbstractIL.IL+MethodBody], Boolean, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef], ILSecurityDecls, ILAttributes) FSharp.Compiler.AbstractIL.IL+ILMethodDefs: ILMethodDef[] AsArray() FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] AsList() FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] FindByName(System.String) @@ -1699,8 +1699,8 @@ FSharp.Compiler.AbstractIL.IL+ILVersionInfo: UInt16 get_Major() FSharp.Compiler.AbstractIL.IL+ILVersionInfo: UInt16 get_Minor() FSharp.Compiler.AbstractIL.IL+ILVersionInfo: UInt16 get_Revision() FSharp.Compiler.AbstractIL.IL+ILVersionInfo: Void .ctor(UInt16, UInt16, UInt16, UInt16) -FSharp.Compiler.AbstractIL.IL+MethodBody+IL: System.Lazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody] Item -FSharp.Compiler.AbstractIL.IL+MethodBody+IL: System.Lazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody] get_Item() +FSharp.Compiler.AbstractIL.IL+MethodBody+IL: Internal.Utilities.Library.InterruptibleLazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody] Item +FSharp.Compiler.AbstractIL.IL+MethodBody+IL: Internal.Utilities.Library.InterruptibleLazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody] get_Item() FSharp.Compiler.AbstractIL.IL+MethodBody+PInvoke: System.Lazy`1[FSharp.Compiler.AbstractIL.IL+PInvokeMethod] Item FSharp.Compiler.AbstractIL.IL+MethodBody+PInvoke: System.Lazy`1[FSharp.Compiler.AbstractIL.IL+PInvokeMethod] get_Item() FSharp.Compiler.AbstractIL.IL+MethodBody+Tags: Int32 Abstract @@ -1730,7 +1730,7 @@ FSharp.Compiler.AbstractIL.IL+MethodBody: Int32 Tag FSharp.Compiler.AbstractIL.IL+MethodBody: Int32 get_Tag() FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody Abstract FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody Native -FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody NewIL(System.Lazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody]) +FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody NewIL(Internal.Utilities.Library.InterruptibleLazy`1[FSharp.Compiler.AbstractIL.IL+ILMethodBody]) FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody NewPInvoke(System.Lazy`1[FSharp.Compiler.AbstractIL.IL+PInvokeMethod]) FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody NotAvailable FSharp.Compiler.AbstractIL.IL+MethodBody: MethodBody get_Abstract() @@ -1842,12 +1842,12 @@ FSharp.Compiler.AbstractIL.IL: ILAttributesStored storeILCustomAttrs(ILAttribute FSharp.Compiler.AbstractIL.IL: ILEventDefs emptyILEvents FSharp.Compiler.AbstractIL.IL: ILEventDefs get_emptyILEvents() FSharp.Compiler.AbstractIL.IL: ILEventDefs mkILEvents(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILEventDef]) -FSharp.Compiler.AbstractIL.IL: ILEventDefs mkILEventsLazy(System.Lazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILEventDef]]) +FSharp.Compiler.AbstractIL.IL: ILEventDefs mkILEventsLazy(Internal.Utilities.Library.InterruptibleLazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILEventDef]]) FSharp.Compiler.AbstractIL.IL: ILExportedTypesAndForwarders mkILExportedTypes(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILExportedTypeOrForwarder]) FSharp.Compiler.AbstractIL.IL: ILFieldDefs emptyILFields FSharp.Compiler.AbstractIL.IL: ILFieldDefs get_emptyILFields() FSharp.Compiler.AbstractIL.IL: ILFieldDefs mkILFields(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILFieldDef]) -FSharp.Compiler.AbstractIL.IL: ILFieldDefs mkILFieldsLazy(System.Lazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILFieldDef]]) +FSharp.Compiler.AbstractIL.IL: ILFieldDefs mkILFieldsLazy(Internal.Utilities.Library.InterruptibleLazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILFieldDef]]) FSharp.Compiler.AbstractIL.IL: ILMethodDefs emptyILMethods FSharp.Compiler.AbstractIL.IL: ILMethodDefs get_emptyILMethods() FSharp.Compiler.AbstractIL.IL: ILMethodDefs mkILMethods(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef]) @@ -1862,7 +1862,7 @@ FSharp.Compiler.AbstractIL.IL: ILNestedExportedTypes mkILNestedExportedTypes(Mic FSharp.Compiler.AbstractIL.IL: ILPropertyDefs emptyILProperties FSharp.Compiler.AbstractIL.IL: ILPropertyDefs get_emptyILProperties() FSharp.Compiler.AbstractIL.IL: ILPropertyDefs mkILProperties(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILPropertyDef]) -FSharp.Compiler.AbstractIL.IL: ILPropertyDefs mkILPropertiesLazy(System.Lazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILPropertyDef]]) +FSharp.Compiler.AbstractIL.IL: ILPropertyDefs mkILPropertiesLazy(Internal.Utilities.Library.InterruptibleLazy`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILPropertyDef]]) FSharp.Compiler.AbstractIL.IL: ILResources emptyILResources FSharp.Compiler.AbstractIL.IL: ILResources get_emptyILResources() FSharp.Compiler.AbstractIL.IL: ILReturn mkILReturn(ILType) @@ -11716,4 +11716,12 @@ FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Ran Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] CreateDictionary(T[]) Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] GetDictionary() Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: T[] GetArray() -Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]]) \ No newline at end of file +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]]) +Internal.Utilities.Library.InterruptibleLazy: T force[T](Internal.Utilities.Library.InterruptibleLazy`1[T]) +Internal.Utilities.Library.InterruptibleLazy`1[T]: Boolean IsValueCreated +Internal.Utilities.Library.InterruptibleLazy`1[T]: Boolean get_IsValueCreated() +Internal.Utilities.Library.InterruptibleLazy`1[T]: Internal.Utilities.Library.InterruptibleLazy`1[T] FromValue(T) +Internal.Utilities.Library.InterruptibleLazy`1[T]: T Force() +Internal.Utilities.Library.InterruptibleLazy`1[T]: T Value +Internal.Utilities.Library.InterruptibleLazy`1[T]: T get_Value() +Internal.Utilities.Library.InterruptibleLazy`1[T]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T]) \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj index 1511ec6ddfc..26bbdc8c235 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj @@ -38,6 +38,9 @@ AssemblyReaderShim.fs + + ModuleReaderCancellationTests.fs + EditorTests.fs diff --git a/tests/service/ModuleReaderCancellationTests.fs b/tests/service/ModuleReaderCancellationTests.fs new file mode 100644 index 00000000000..b7b962b7a04 --- /dev/null +++ b/tests/service/ModuleReaderCancellationTests.fs @@ -0,0 +1,255 @@ +module FSharp.Compiler.Service.Tests.ModuleReaderCancellationTests + +open System +open System.IO +open System.Reflection +open System.Threading +open FSharp.Compiler +open FSharp.Compiler.AbstractIL.IL +open FSharp.Compiler.AbstractIL.ILBinaryReader +open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.Text +open FsUnit +open Internal.Utilities.Library +open NUnit.Framework + +let mutable private cts = new CancellationTokenSource() +let mutable private wasCancelled = false + +let runCancelFirstTime f = + let mutable requestCount = 0 + fun () -> + if requestCount = 0 then + cts.Cancel() + + requestCount <- requestCount + 1 + Cancellable.CheckAndThrow() + + f () + + +module ModuleReader = + let subsystemVersion = 4, 0 + let useHighEntropyVA = false + let metadataVersion = String.Empty + let flags = 0 + let exportedTypes = mkILExportedTypes [] + + let mkCtor () = + let name = ".ctor" + let methodAttrs = + MethodAttributes.Public ||| + MethodAttributes.HideBySig ||| + MethodAttributes.NewSlot ||| + MethodAttributes.SpecialName + + let callingConv = Callconv(ILThisConvention.Instance, ILArgConvention.Default) + let parameters = [] + let ret = mkILReturn ILType.Void + let genericParams = [] + let customAttrs = mkILCustomAttrs [] + + let implAttributes = MethodImplAttributes.Managed + let body = InterruptibleLazy.FromValue MethodBody.NotAvailable + let securityDecls = emptyILSecurityDecls + let isEntryPoint = false + + ILMethodDef(name, methodAttrs, implAttributes, callingConv, parameters, ret, body, isEntryPoint, genericParams, + securityDecls, customAttrs) + + +type ModuleReader(name, typeDefs) = + let assemblyName = $"{name}.dll" + let moduleName = name + let isDll = true + + let ilModuleDef = + mkILSimpleModule + assemblyName moduleName isDll + ModuleReader.subsystemVersion + ModuleReader.useHighEntropyVA + typeDefs + None None + ModuleReader.flags + ModuleReader.exportedTypes + "" + + member val Timestamp = DateTime.UtcNow + member val Path = Path.Combine(Path.GetTempPath(), assemblyName) + + interface ILModuleReader with + member x.ILModuleDef = ilModuleDef + member x.ILAssemblyRefs = [] + member x.Dispose() = () + + +type PreTypeDefData = + { Name: string + Namespace: string list + HasCtor: bool + CancelOnImport: bool } + + member this.TypeDef = + let name = + match this.Namespace with + | [] -> this.Name + | ns -> + let ns = ns |> String.concat "." + $"{ns}.{this.Name}" + + let methodsDefs = + if this.HasCtor then + let mkCtor = runCancelFirstTime (fun _ -> [| ModuleReader.mkCtor () |]) + mkILMethodsComputed mkCtor + else + mkILMethods [] + + let typeAttributes = TypeAttributes.Public + let customAttrs = mkILCustomAttrs [] + ILTypeDef(this.Name, typeAttributes, ILTypeDefLayout.Auto, [], [], + None, methodsDefs, mkILTypeDefs [], mkILFields [], emptyILMethodImpls, mkILEvents [], mkILProperties [], false, + emptyILSecurityDecls, customAttrs) + +type PreTypeDef(data: PreTypeDefData) = + let typeDef = data.TypeDef + let getTypeDef = + if data.CancelOnImport then runCancelFirstTime (fun _ -> typeDef) else (fun _ -> typeDef) + + interface ILPreTypeDef with + member x.Name = data.Name + member x.Namespace = data.Namespace + member x.GetTypeDef() = getTypeDef () + + +let createPreTypeDefs typeData = + typeData + |> Array.ofList + |> Array.map (fun data -> PreTypeDef data :> ILPreTypeDef) + +let referenceReaderProject getPreTypeDefs options = + let reader = new ModuleReader("Reference", mkILTypeDefsComputed getPreTypeDefs) + + let project = FSharpReferencedProject.ILModuleReference( + reader.Path, (fun _ -> reader.Timestamp), (fun _ -> reader) + ) + + { options with ReferencedProjects = [| project |]; OtherOptions = Array.append options.OtherOptions [| $"-r:{reader.Path}"|] } + +let parseAndCheck path source options = + cts <- new CancellationTokenSource() + wasCancelled <- false + + try + match Async.RunSynchronously(checker.ParseAndCheckFileInProject(path, 0, SourceText.ofString source, options), cancellationToken = cts.Token) with + | fileResults, FSharpCheckFileAnswer.Aborted -> None + | fileResults, FSharpCheckFileAnswer.Succeeded results -> Some results + with :? OperationCanceledException -> + wasCancelled <- true + None + + + +let source1 = """ +module Module + +let t: T = T() +""" + +let source2 = """ +module Module + +open Ns1.Ns2 + +let t: T = T() +""" + + +[] +let ``Type defs 01 - assembly import`` () = + let source = source1 + + let getPreTypeDefs typeData = runCancelFirstTime (fun _ -> createPreTypeDefs typeData) + let typeDefs = getPreTypeDefs [ { Name = "T"; Namespace = []; HasCtor = false; CancelOnImport = false } ] + let path, options = mkTestFileAndOptions source [||] + let options = referenceReaderProject typeDefs options + + // First request, should be cancelled inside getPreTypeDefs + // The cancellation happens in side CombineImportedAssembliesTask, so background builder node fails to be evaluated + parseAndCheck path source options |> ignore + wasCancelled |> shouldEqual true + + // Second request, should succeed, with complete analysis + match parseAndCheck path source options with + | Some results -> + wasCancelled |> shouldEqual false + + results.Diagnostics + |> Array.map (fun e -> e.Message) + |> shouldEqual [| "No constructors are available for the type 'T'" |] + + | None -> failwith "Expecting results" + + +[] +let ``Type defs 02 - assembly import`` () = + let source = source1 + + let typeDefs = fun _ -> createPreTypeDefs [ { Name = "T"; Namespace = ["Ns"]; HasCtor = false; CancelOnImport = true } ] + let path, options = mkTestFileAndOptions source [||] + let options = referenceReaderProject typeDefs options + + parseAndCheck path source options |> ignore + wasCancelled |> shouldEqual false + + match parseAndCheck path source options with + | Some results -> + wasCancelled |> shouldEqual false + results.Diagnostics |> Array.isEmpty |> shouldEqual false + | None -> failwith "Expecting results" + + +[] +let ``Type defs 03 - type import`` () = + let source = source2 + + let typeDefs = fun _ -> createPreTypeDefs [ { Name = "T"; Namespace = ["Ns1"; "Ns2"]; HasCtor = false; CancelOnImport = true } ] + let path, options = mkTestFileAndOptions source [||] + let options = referenceReaderProject typeDefs options + + // First request, should be cancelled inside GetTypeDef + // This shouldn't be cached due to InterruptibleLazy + parseAndCheck path source options |> ignore + wasCancelled |> shouldEqual true + + // Second request, should succeed, with complete analysis + match parseAndCheck path source options with + | Some results -> + wasCancelled |> shouldEqual false + + results.Diagnostics + |> Array.map (fun e -> e.Message) + |> shouldEqual [| "No constructors are available for the type 'T'" |] + + | None -> failwith "Expecting results" + + +[] +let ``Type defs 04 - ctor import`` () = + let source = source1 + + let typeDefs = fun _ -> createPreTypeDefs [ { Name = "T"; Namespace = []; HasCtor = true; CancelOnImport = false } ] + let path, options = mkTestFileAndOptions source [||] + let options = referenceReaderProject typeDefs options + + // First request, should be cancelled inside ILMethodDefs + // This shouldn't be cached due to InterruptibleLazy + parseAndCheck path source options |> ignore + wasCancelled |> shouldEqual true + + // Second request, should succeed, with complete analysis + match parseAndCheck path source options with + | Some results -> + wasCancelled |> shouldEqual false + results.Diagnostics |> Array.isEmpty |> shouldEqual true + + | None -> failwith "Expecting results"