From a9b3ea54a7ff548b4ba822b4a0d902466e40d62f Mon Sep 17 00:00:00 2001 From: Ross Kuehl <94796738+rosskuehl@users.noreply.github.com> Date: Wed, 4 Jan 2023 04:59:30 -0500 Subject: [PATCH 1/3] fix isRecursive binding in ServiceParseTreeWalk.fs (#14518) * fix isRecursive binding in ServiceParseTreeWalk.fs * use named access on ident pattern match --- src/Compiler/Service/ServiceParseTreeWalk.fs | 2 +- tests/service/TreeVisitorTests.fs | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index 2a335d274e9..8415ec401fd 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -594,7 +594,7 @@ module SyntaxTraversal = | SynExpr.TypeApp (synExpr, _, _synTypeList, _commas, _, _, _range) -> traverseSynExpr synExpr - | SynExpr.LetOrUse (_, isRecursive, synBindingList, synExpr, range, _) -> + | SynExpr.LetOrUse (isRecursive, _, synBindingList, synExpr, range, _) -> match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with | None -> [ diff --git a/tests/service/TreeVisitorTests.fs b/tests/service/TreeVisitorTests.fs index 9bcfa47796a..58bda80d487 100644 --- a/tests/service/TreeVisitorTests.fs +++ b/tests/service/TreeVisitorTests.fs @@ -58,4 +58,20 @@ let ``Visit enum definition test`` () = match SyntaxTraversal.Traverse(pos0, parseTree, visitor) with | Some [ SynEnumCase (_, SynIdent(id1,_), _, _, _, _, _); SynEnumCase (_, SynIdent(id2,_), _, _, _, _, _) ] when id1.idText = "A" && id2.idText = "B" -> () - | _ -> failwith "Did not visit enum definition" \ No newline at end of file + | _ -> failwith "Did not visit enum definition" + +[] +let ``Visit recursive let binding`` () = + let visitor = + { new SyntaxVisitorBase<_>() with + member x.VisitExpr(_, _, defaultTraverse, expr) = defaultTraverse expr + member x.VisitLetOrUse(_, isRecursive, _, bindings, _) = + if not isRecursive then failwith $"{nameof isRecursive} should be true" + Some bindings } + + let source = "let rec fib n = if n < 2 then n else fib (n - 1) + fib (n - 2) in fib 10" + let parseTree = parseSourceCode("C:\\test.fs", source) + + match SyntaxTraversal.Traverse(pos0, parseTree, visitor) with + | Some [ SynBinding(valData = SynValData(valInfo = SynValInfo(curriedArgInfos = [ [ SynArgInfo(ident = Some id) ] ]))) ] when id.idText = "n" -> () + | _ -> failwith "Did not visit recursive let binding" \ No newline at end of file From 73c90745cd50cbdcb3eb064c6f97edf3ccb3cd4b Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 5 Jan 2023 10:37:34 +0100 Subject: [PATCH 2/3] Ditch code that was needed because of a runtime bug, that was fixed in the meantime (#14509) --- src/FSharp.Core/fslib-extra-pervasives.fs | 44 +------------------ .../ExtraTopLevelOperatorsTests.fs | 4 +- 2 files changed, 3 insertions(+), 45 deletions(-) diff --git a/src/FSharp.Core/fslib-extra-pervasives.fs b/src/FSharp.Core/fslib-extra-pervasives.fs index 01fd7018b11..c04d02721f4 100644 --- a/src/FSharp.Core/fslib-extra-pervasives.fs +++ b/src/FSharp.Core/fslib-extra-pervasives.fs @@ -51,10 +51,7 @@ module ExtraTopLevelOperators = makeSafeKey: 'Key -> 'SafeKey, getKey: 'SafeKey -> 'Key ) = -#if NETSTANDARD - static let emptyEnumerator = - (Array.empty> :> seq<_>).GetEnumerator() -#endif + member _.Count = t.Count // Give a read-only view of the dictionary @@ -169,47 +166,8 @@ module ExtraTopLevelOperators = member _.GetEnumerator() = // We use an array comprehension here instead of seq {} as otherwise we get incorrect // IEnumerator.Reset() and IEnumerator.Current semantics. - // Coreclr has a bug with SZGenericEnumerators --- implement a correct enumerator. On desktop use the desktop implementation because it's ngened. -#if !NETSTANDARD let kvps = [| for (KeyValue (k, v)) in t -> KeyValuePair(getKey k, v) |] :> seq<_> kvps.GetEnumerator() -#else - let endIndex = t.Count - - if endIndex = 0 then - emptyEnumerator - else - let kvps = [| for (KeyValue (k, v)) in t -> KeyValuePair(getKey k, v) |] - let mutable index = -1 - - let current () = - if index < 0 then - raise <| InvalidOperationException(SR.GetString(SR.enumerationNotStarted)) - - if index >= endIndex then - raise <| InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished)) - - kvps.[index] - - { new IEnumerator<_> with - member _.Current = current () - interface System.Collections.IEnumerator with - member _.Current = box (current ()) - - member _.MoveNext() = - if index < endIndex then - index <- index + 1 - index < endIndex - else - false - - member _.Reset() = - index <- -1 - interface System.IDisposable with - member _.Dispose() = - () - } -#endif interface System.Collections.IEnumerable with member _.GetEnumerator() = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Core/ExtraTopLevelOperatorsTests.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Core/ExtraTopLevelOperatorsTests.fs index 147edbe1916..9c4379fd459 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Core/ExtraTopLevelOperatorsTests.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Core/ExtraTopLevelOperatorsTests.fs @@ -8,7 +8,7 @@ open System.Collections.Generic type DictTests () = [] - member this.IEnumerable() = + member this.IEnumerableOnDict() = // Legit IE let ie = (dict [|(1,1);(2,4);(3,9)|]) :> IEnumerable let enum = ie.GetEnumerator() @@ -38,7 +38,7 @@ type DictTests () = CheckThrowsInvalidOperationExn(fun () -> enum.Current |> ignore) [] - member this.IEnumerable_T() = + member this.IEnumerable_T_OnDict() = // Legit IE let ie = (dict [|(1,1);(2,4);(3,9)|]) :> IEnumerable> let enum = ie.GetEnumerator() From 1b3f86c2d9278d8e73751e11f3887e09eae1bd8b Mon Sep 17 00:00:00 2001 From: Christer van der Meeren Date: Thu, 5 Jan 2023 16:03:10 +0100 Subject: [PATCH 3/3] Use recommended postfix notation for generics (#14530) --- src/Compiler/Driver/CompilerConfig.fs | 2 +- src/Compiler/Driver/CompilerImports.fs | 2 +- src/Compiler/Driver/CompilerImports.fsi | 2 +- src/Compiler/Driver/CompilerOptions.fs | 2 +- src/Compiler/Driver/CompilerOptions.fsi | 2 +- src/Compiler/Service/FSharpCheckerResults.fs | 2 +- src/Compiler/TypedTree/TypedTreeOps.fs | 4 ++-- src/Compiler/TypedTree/TypedTreeOps.fsi | 24 ++++++++++---------- src/FSharp.Core/result.fsi | 6 ++--- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 54e45ead3cc..e945c9564a4 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -300,7 +300,7 @@ type ImportedAssembly = IsProviderGenerated: bool mutable TypeProviders: Tainted list #endif - FSharpOptimizationData: Microsoft.FSharp.Control.Lazy> + FSharpOptimizationData: Microsoft.FSharp.Control.Lazy } type AvailableImportedAssembly = diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 22162611f0c..69cb69d4106 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -338,7 +338,7 @@ type ImportedAssembly = IsProviderGenerated: bool mutable TypeProviders: Tainted list #endif - FSharpOptimizationData: Microsoft.FSharp.Control.Lazy> + FSharpOptimizationData: Microsoft.FSharp.Control.Lazy } type AvailableImportedAssembly = diff --git a/src/Compiler/Driver/CompilerImports.fsi b/src/Compiler/Driver/CompilerImports.fsi index 30bb4333f77..f9fa17487ae 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: Lazy } /// Tables of assembly resolutions [] diff --git a/src/Compiler/Driver/CompilerOptions.fs b/src/Compiler/Driver/CompilerOptions.fs index 6d5da331a82..a4e0aab19e8 100644 --- a/src/Compiler/Driver/CompilerOptions.fs +++ b/src/Compiler/Driver/CompilerOptions.fs @@ -69,7 +69,7 @@ and CompilerOption = name: string * argumentDescriptionString: string * actionSpec: OptionSpec * - deprecationError: Option * + deprecationError: exn option * helpText: string option and CompilerOptionBlock = diff --git a/src/Compiler/Driver/CompilerOptions.fsi b/src/Compiler/Driver/CompilerOptions.fsi index 49151028426..bb2034b93d5 100644 --- a/src/Compiler/Driver/CompilerOptions.fsi +++ b/src/Compiler/Driver/CompilerOptions.fsi @@ -36,7 +36,7 @@ and CompilerOption = name: string * argumentDescriptionString: string * actionSpec: OptionSpec * - deprecationError: Option * + deprecationError: exn option * helpText: string option and CompilerOptionBlock = diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index f2b88684b5c..25d1cbeba0b 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -834,7 +834,7 @@ type internal TypeCheckInfo if p >= 0 then Some p else None /// Build a CompetionItem - let CompletionItem (ty: ValueOption) (assemblySymbol: ValueOption) (item: ItemWithInst) = + let CompletionItem (ty: TyconRef voption) (assemblySymbol: AssemblySymbol voption) (item: ItemWithInst) = let kind = match item.Item with | Item.FakeInterfaceCtor _ diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index 1ff908d445a..a1146828d6f 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -1604,13 +1604,13 @@ type TyconRefMultiMap<'T>(contents: TyconRefMap<'T list>) = //-------------------------------------------------------------------------- /// Try to create a EntityRef suitable for accessing the given Entity from another assembly -let tryRescopeEntity viewedCcu (entity: Entity) : ValueOption = +let tryRescopeEntity viewedCcu (entity: Entity) : EntityRef voption = match entity.PublicPath with | Some pubpath -> ValueSome (ERefNonLocal (rescopePubPath viewedCcu pubpath)) | None -> ValueNone /// Try to create a ValRef suitable for accessing the given Val from another assembly -let tryRescopeVal viewedCcu (entityRemap: Remap) (vspec: Val) : ValueOption = +let tryRescopeVal viewedCcu (entityRemap: Remap) (vspec: Val) : ValRef voption = match vspec.PublicPath with | Some (ValPubPath(p, fullLinkageKey)) -> // The type information in the val linkage doesn't need to keep any information to trait solutions. diff --git a/src/Compiler/TypedTree/TypedTreeOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.fsi index ae58019683a..a2944d2cbd0 100755 --- a/src/Compiler/TypedTree/TypedTreeOps.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.fsi @@ -665,7 +665,7 @@ val isTyparTy: TcGlobals -> TType -> bool val isAnyParTy: TcGlobals -> TType -> bool -val tryAnyParTy: TcGlobals -> TType -> ValueOption +val tryAnyParTy: TcGlobals -> TType -> Typar voption val tryAnyParTyOption: TcGlobals -> TType -> Typar option @@ -679,26 +679,26 @@ val isProvenUnionCaseTy: TType -> bool val isAppTy: TcGlobals -> TType -> bool -val tryAppTy: TcGlobals -> TType -> ValueOption +val tryAppTy: TcGlobals -> TType -> (TyconRef * TypeInst) voption val destAppTy: TcGlobals -> TType -> TyconRef * TypeInst val tcrefOfAppTy: TcGlobals -> TType -> TyconRef -val tryTcrefOfAppTy: TcGlobals -> TType -> ValueOption +val tryTcrefOfAppTy: TcGlobals -> TType -> TyconRef voption -val tryDestTyparTy: TcGlobals -> TType -> ValueOption +val tryDestTyparTy: TcGlobals -> TType -> Typar voption -val tryDestFunTy: TcGlobals -> TType -> ValueOption +val tryDestFunTy: TcGlobals -> TType -> (TType * TType) voption -val tryDestAnonRecdTy: TcGlobals -> TType -> ValueOption +val tryDestAnonRecdTy: TcGlobals -> TType -> (AnonRecdTypeInfo * TType list) voption val argsOfAppTy: TcGlobals -> TType -> TypeInst val mkInstForAppTy: TcGlobals -> TType -> TyparInstantiation /// Try to get a TyconRef for a type without erasing type abbreviations -val tryNiceEntityRefOfTy: TType -> ValueOption +val tryNiceEntityRefOfTy: TType -> TyconRef voption val tryNiceEntityRefOfTyOption: TType -> TyconRef option @@ -1089,7 +1089,7 @@ val tagEntityRefName: xref: EntityRef -> name: string -> TaggedText /// Return the full text for an item as we want it displayed to the user as a fully qualified entity val fullDisplayTextOfModRef: ModuleOrNamespaceRef -> string -val fullDisplayTextOfParentOfModRef: ModuleOrNamespaceRef -> ValueOption +val fullDisplayTextOfParentOfModRef: ModuleOrNamespaceRef -> string voption val fullDisplayTextOfValRef: ValRef -> string @@ -1303,10 +1303,10 @@ val wrapModuleOrNamespaceTypeInNamespace: val wrapModuleOrNamespaceType: Ident -> CompilationPath -> ModuleOrNamespaceType -> ModuleOrNamespace /// Given a namespace, module or type definition, try to produce a reference to that entity. -val tryRescopeEntity: CcuThunk -> Entity -> ValueOption +val tryRescopeEntity: CcuThunk -> Entity -> EntityRef voption /// Given a value definition, try to produce a reference to that value. Fails for local values. -val tryRescopeVal: CcuThunk -> Remap -> Val -> ValueOption +val tryRescopeVal: CcuThunk -> Remap -> Val -> ValRef voption /// Make the substitution (remapping) table for viewing a module or namespace 'from the outside' /// @@ -1526,7 +1526,7 @@ val isOptionTy: TcGlobals -> TType -> bool val destOptionTy: TcGlobals -> TType -> TType /// Try to take apart an option type -val tryDestOptionTy: TcGlobals -> TType -> ValueOption +val tryDestOptionTy: TcGlobals -> TType -> TType voption /// Try to take apart an option type val destValueOptionTy: TcGlobals -> TType -> TType @@ -1535,7 +1535,7 @@ val destValueOptionTy: TcGlobals -> TType -> TType val isNullableTy: TcGlobals -> TType -> bool /// Try to take apart a System.Nullable type -val tryDestNullableTy: TcGlobals -> TType -> ValueOption +val tryDestNullableTy: TcGlobals -> TType -> TType voption /// Take apart a System.Nullable type val destNullableTy: TcGlobals -> TType -> TType diff --git a/src/FSharp.Core/result.fsi b/src/FSharp.Core/result.fsi index 2641fd1eff3..837f8b4d06c 100644 --- a/src/FSharp.Core/result.fsi +++ b/src/FSharp.Core/result.fsi @@ -281,7 +281,7 @@ module Result = /// /// [] - val toList: result: Result<'T, 'Error> -> List<'T> + val toList: result: Result<'T, 'Error> -> 'T list /// Convert the result to an Option value. /// @@ -296,7 +296,7 @@ module Result = /// /// [] - val toOption: result: Result<'T, 'Error> -> Option<'T> + val toOption: result: Result<'T, 'Error> -> 'T option /// Convert the result to an Option value. /// @@ -311,4 +311,4 @@ module Result = /// /// [] - val toValueOption: result: Result<'T, 'Error> -> ValueOption<'T> + val toValueOption: result: Result<'T, 'Error> -> 'T voption