From f82d7c9857fc7457fcbd0e42926fb85162299828 Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 24 Aug 2016 12:45:14 -0400 Subject: [PATCH 1/7] print public fields --- src/utils/sformat.fs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/utils/sformat.fs b/src/utils/sformat.fs index eec0d6a7a7..b2ac302b7b 100644 --- a/src/utils/sformat.fs +++ b/src/utils/sformat.fs @@ -709,8 +709,7 @@ namespace Microsoft.FSharp.Text.StructuredFormat // pprinter: anyL - support functions // -------------------------------------------------------------------- - let getProperty (obj: obj) name = - let ty = obj.GetType() + let getProperty (ty: Type) (obj: obj) name = #if FX_ATLEAST_PORTABLE let prop = ty.GetProperty(name, (BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)) if isNotNull prop then prop.GetValue(obj,[||]) @@ -732,6 +731,9 @@ namespace Microsoft.FSharp.Text.StructuredFormat ty.InvokeMember(name, (BindingFlags.GetProperty ||| BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic), null, obj, [| |],CultureInfo.InvariantCulture) #endif #endif + let getField obj (fieldInfo: FieldInfo) = + fieldInfo.GetValue(obj) + let formatChar isChar c = match c with | '\'' when isChar -> "\\\'" @@ -862,7 +864,7 @@ namespace Microsoft.FSharp.Text.StructuredFormat let postText = m.Groups.["post"].Value // Everything after the closing bracket let prop = replaceEscapedBrackets(m.Groups.["prop"].Value) // Unescape everything between the opening and closing brackets - match catchExn (fun () -> getProperty x prop) with + match catchExn (fun () -> getProperty ty x prop) with | Choice2Of2 e -> Some (wordL ("")) | Choice1Of2 alternativeObj -> try @@ -1102,8 +1104,11 @@ namespace Microsoft.FSharp.Text.StructuredFormat #else let props = ty.GetProperties(BindingFlags.GetField ||| BindingFlags.Instance ||| BindingFlags.Public) #endif - let props = - props |> Array.filter (fun pi -> + let fields = ty.GetFields(BindingFlags.Instance ||| BindingFlags.Public) + let propsAndFields = + props |> Array.map (fun i -> i :> MemberInfo) + |> Array.append (Array.map (fun i -> i :> MemberInfo) fields) + |> Array.filter (fun pi -> // check if property is annotated with System.Diagnostics.DebuggerBrowsable(Never). // Its evaluation may have unexpected side effects and\or block printing. match Seq.toArray (pi.GetCustomAttributes(typeof, false)) with @@ -1114,17 +1119,21 @@ namespace Microsoft.FSharp.Text.StructuredFormat // massively reign in deep printing of properties let nDepth = depthLim/10 #if FX_ATLEAST_PORTABLE - System.Array.Sort((props),{ new System.Collections.Generic.IComparer with member this.Compare(p1,p2) = compare (p1.Name) (p2.Name) } ); + System.Array.Sort((propsAndFields),{ new System.Collections.Generic.IComparer with member this.Compare(p1,p2) = compare (p1.Name) (p2.Name) } ); #else - System.Array.Sort((props:>System.Array),{ new System.Collections.IComparer with member this.Compare(p1,p2) = compare ((p1 :?> PropertyInfo).Name) ((p2 :?> PropertyInfo).Name) } ); + System.Array.Sort((propsAndFields:>System.Array),{ new System.Collections.IComparer with member this.Compare(p1,p2) = compare ((p1 :?> MemberInfo).Name) ((p2 :?> MemberInfo).Name) } ); #endif - if props.Length = 0 || (nDepth <= 0) then basicL + if propsAndFields.Length = 0 || (nDepth <= 0) then basicL else basicL --- - (props + (propsAndFields |> Array.toList - |> List.map (fun p -> (p.Name,(try Some (objL nDepth Precedence.BracketIfTuple (getProperty obj p.Name)) - with _ -> None))) + |> List.map + (fun m -> + (m.Name, + (try Some (objL nDepth Precedence.BracketIfTuple (getProperty ty obj m.Name)) + with _ -> try Some (objL nDepth Precedence.BracketIfTuple (getField obj (m :?> FieldInfo))) + with _ -> None))) |> makePropertiesL) | _ -> basicL | UnitValue -> countNodes 1; measureL From ef593041ca0a22a46a95c16e180490929596776c Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 24 Aug 2016 18:19:11 -0400 Subject: [PATCH 2/7] Added test and cleanup --- src/utils/sformat.fs | 10 +++++----- .../Source/InteractiveSession/Misc/PublicField.fsx | 12 ++++++++++++ .../fsharpqa/Source/InteractiveSession/Misc/env.lst | 4 +++- 3 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx diff --git a/src/utils/sformat.fs b/src/utils/sformat.fs index b2ac302b7b..c1a4460f5b 100644 --- a/src/utils/sformat.fs +++ b/src/utils/sformat.fs @@ -1104,10 +1104,10 @@ namespace Microsoft.FSharp.Text.StructuredFormat #else let props = ty.GetProperties(BindingFlags.GetField ||| BindingFlags.Instance ||| BindingFlags.Public) #endif - let fields = ty.GetFields(BindingFlags.Instance ||| BindingFlags.Public) + let fields = ty.GetFields(BindingFlags.Instance ||| BindingFlags.Public) |> Array.map (fun i -> i :> MemberInfo) let propsAndFields = props |> Array.map (fun i -> i :> MemberInfo) - |> Array.append (Array.map (fun i -> i :> MemberInfo) fields) + |> Array.append fields |> Array.filter (fun pi -> // check if property is annotated with System.Diagnostics.DebuggerBrowsable(Never). // Its evaluation may have unexpected side effects and\or block printing. @@ -1121,19 +1121,19 @@ namespace Microsoft.FSharp.Text.StructuredFormat #if FX_ATLEAST_PORTABLE System.Array.Sort((propsAndFields),{ new System.Collections.Generic.IComparer with member this.Compare(p1,p2) = compare (p1.Name) (p2.Name) } ); #else - System.Array.Sort((propsAndFields:>System.Array),{ new System.Collections.IComparer with member this.Compare(p1,p2) = compare ((p1 :?> MemberInfo).Name) ((p2 :?> MemberInfo).Name) } ); + System.Array.Sort((propsAndFields :> System.Array),{ new System.Collections.IComparer with member this.Compare(p1,p2) = compare ((p1 :?> MemberInfo).Name) ((p2 :?> MemberInfo).Name) } ); #endif if propsAndFields.Length = 0 || (nDepth <= 0) then basicL else basicL --- (propsAndFields - |> Array.toList - |> List.map + |> Array.map (fun m -> (m.Name, (try Some (objL nDepth Precedence.BracketIfTuple (getProperty ty obj m.Name)) with _ -> try Some (objL nDepth Precedence.BracketIfTuple (getField obj (m :?> FieldInfo))) with _ -> None))) + |> Array.toList |> makePropertiesL) | _ -> basicL | UnitValue -> countNodes 1; measureL diff --git a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx new file mode 100644 index 0000000000..752b74f9f1 --- /dev/null +++ b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx @@ -0,0 +1,12 @@ +// #Regression #NoMT #FSI +// Public fields did not print. +//val it : PublicField = FSI_0002+PublicField {X = 2;\n Y = 1;} +[] +type PublicField = + val X : int + val mutable Y : int + new (x) = { X = x ; Y = 1 } + +let t2 = PublicField(2);; +t2;; +#q;; \ No newline at end of file diff --git a/tests/fsharpqa/Source/InteractiveSession/Misc/env.lst b/tests/fsharpqa/Source/InteractiveSession/Misc/env.lst index 03dcd5eb60..1380330716 100644 --- a/tests/fsharpqa/Source/InteractiveSession/Misc/env.lst +++ b/tests/fsharpqa/Source/InteractiveSession/Misc/env.lst @@ -29,8 +29,10 @@ ReqENU SOURCE=E_InterfaceCrossConstrained02.fsx COMPILE_ONLY=1 FSIMODE=PIPE SC SOURCE=ToStringNull.fsx COMPILE_ONLY=1 FSIMODE=PIPE SCFLAGS="--nologo" # ToStringNull.fsx - SOURCE=EnumerateSets.fsx COMPILE_ONLY=1 FSIMODE=PIPE SCFLAGS="--nologo" # EnumerateSets.fsx + SOURCE=EnumerateSets.fsx COMPILE_ONLY=1 FSIMODE=PIPE SCFLAGS="--nologo" # EnumerateSets.fsx + SOURCE=PublicField.fsx COMPILE_ONLY=1 FSIMODE=PIPE SCFLAGS="--nologo" # PublicField.fsx + # These are the regression tests for FSHARP1.0:5427 # The scenario is a bit convoluted because of the way we end up doing the verification # In the last 2 cases, the verification is achieved by dumping the output of FSI to a file From a582a14da54c6698798c94fa0d997fa6bb0f2c48 Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 24 Aug 2016 18:20:06 -0400 Subject: [PATCH 3/7] ending with a newline --- tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx index 752b74f9f1..5a42e5cfd3 100644 --- a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx +++ b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx @@ -9,4 +9,4 @@ type PublicField = let t2 = PublicField(2);; t2;; -#q;; \ No newline at end of file +#q;; From 4f4d8145fa7a262479649fb9e22a96a64b6dab07 Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 24 Aug 2016 19:17:00 -0400 Subject: [PATCH 4/7] escaped braces --- tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx index 5a42e5cfd3..7c31d421c4 100644 --- a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx +++ b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx @@ -1,6 +1,6 @@ // #Regression #NoMT #FSI // Public fields did not print. -//val it : PublicField = FSI_0002+PublicField {X = 2;\n Y = 1;} +//val it : PublicField = FSI_0002+PublicField \{X = 2;\n Y = 1;\} [] type PublicField = val X : int From 28882cc15df4ecf7c2a027a92bf2bc80422e9632 Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 24 Aug 2016 20:14:07 -0400 Subject: [PATCH 5/7] maybe it needs the spaces... --- tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx index 7c31d421c4..0a0f2abe1e 100644 --- a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx +++ b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx @@ -1,6 +1,6 @@ // #Regression #NoMT #FSI // Public fields did not print. -//val it : PublicField = FSI_0002+PublicField \{X = 2;\n Y = 1;\} +//val it : PublicField = FSI_0002+PublicField \{X = 2;\n Y = 1;\} [] type PublicField = val X : int From 69e55b69ea5f705f8d50706f3df3922b775caf50 Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 24 Aug 2016 21:18:10 -0400 Subject: [PATCH 6/7] fix test --- tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx index 0a0f2abe1e..d3ac670bff 100644 --- a/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx +++ b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx @@ -1,6 +1,7 @@ // #Regression #NoMT #FSI // Public fields did not print. -//val it : PublicField = FSI_0002+PublicField \{X = 2;\n Y = 1;\} +//val it : PublicField = FSI_0002+PublicField \{X = 2; +// Y = 1;\} [] type PublicField = val X : int From 389095c2b8a876dc77f15041b211b939d7e82f9d Mon Sep 17 00:00:00 2001 From: liboz Date: Thu, 25 Aug 2016 15:21:51 -0400 Subject: [PATCH 7/7] Additional cleanup as suggested by feedback --- src/utils/sformat.fs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/utils/sformat.fs b/src/utils/sformat.fs index c1a4460f5b..e106245e18 100644 --- a/src/utils/sformat.fs +++ b/src/utils/sformat.fs @@ -829,7 +829,7 @@ namespace Microsoft.FSharp.Text.StructuredFormat Some (wordL (x.ToString())) else // Try the StructuredFormatDisplayAttribute extensibility attribute - match x.GetType().GetCustomAttributes (typeof, true) with + match ty.GetCustomAttributes (typeof, true) with | null | [| |] -> None | res -> let attr = (res.[0] :?> StructuredFormatDisplayAttribute) @@ -1021,7 +1021,7 @@ namespace Microsoft.FSharp.Text.StructuredFormat #else wordL (formatString s) #endif - | :? System.Array as arr -> + | :? Array as arr -> match arr.Rank with | 1 -> let n = arr.Length @@ -1046,18 +1046,17 @@ namespace Microsoft.FSharp.Text.StructuredFormat // Format 'set' and 'map' nicely | _ when - (let ty = obj.GetType() - ty.IsGenericType && (ty.GetGenericTypeDefinition() = typedefof> + (ty.IsGenericType && (ty.GetGenericTypeDefinition() = typedefof> || ty.GetGenericTypeDefinition() = typedefof>) ) -> - let ty = obj.GetType() let word = if ty.GetGenericTypeDefinition() = typedefof> then "map" else "set" let possibleKeyValueL v = + let tyv = v.GetType() if word = "map" && (match v with null -> false | _ -> true) && - v.GetType().IsGenericType && - v.GetType().GetGenericTypeDefinition() = typedefof> then - objL depthLim Precedence.BracketIfTuple (v.GetType().GetProperty("Key").GetValue(v, [| |]), - v.GetType().GetProperty("Value").GetValue(v, [| |])) + tyv.IsGenericType && + tyv.GetGenericTypeDefinition() = typedefof> then + objL depthLim Precedence.BracketIfTuple (tyv.GetProperty("Key").GetValue(v, [| |]), + tyv.GetProperty("Value").GetValue(v, [| |])) else objL depthLim Precedence.BracketIfTuple v let it = (obj :?> System.Collections.IEnumerable).GetEnumerator() @@ -1091,7 +1090,7 @@ namespace Microsoft.FSharp.Text.StructuredFormat // Also, in the declared values case, if the sequence is actually a known non-lazy type (list, array etc etc) we could print it. wordL "" |> showModeFilter | _ -> - if showMode = ShowTopLevelBinding && typeUsesSystemObjectToString (obj.GetType()) then + if showMode = ShowTopLevelBinding && typeUsesSystemObjectToString ty then emptyL else countNodes 1 @@ -1119,9 +1118,9 @@ namespace Microsoft.FSharp.Text.StructuredFormat // massively reign in deep printing of properties let nDepth = depthLim/10 #if FX_ATLEAST_PORTABLE - System.Array.Sort((propsAndFields),{ new System.Collections.Generic.IComparer with member this.Compare(p1,p2) = compare (p1.Name) (p2.Name) } ); + Array.Sort((propsAndFields),{ new IComparer with member this.Compare(p1,p2) = compare (p1.Name) (p2.Name) } ); #else - System.Array.Sort((propsAndFields :> System.Array),{ new System.Collections.IComparer with member this.Compare(p1,p2) = compare ((p1 :?> MemberInfo).Name) ((p2 :?> MemberInfo).Name) } ); + Array.Sort((propsAndFields :> Array),{ new System.Collections.IComparer with member this.Compare(p1,p2) = compare ((p1 :?> MemberInfo).Name) ((p2 :?> MemberInfo).Name) } ); #endif if propsAndFields.Length = 0 || (nDepth <= 0) then basicL