diff --git a/src/utils/sformat.fs b/src/utils/sformat.fs index eec0d6a7a70..e106245e185 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 -> "\\\'" @@ -827,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) @@ -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 @@ -1019,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 @@ -1044,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() @@ -1089,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 @@ -1102,8 +1103,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) |> Array.map (fun i -> i :> MemberInfo) + let propsAndFields = + props |> Array.map (fun i -> i :> MemberInfo) + |> 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. match Seq.toArray (pi.GetCustomAttributes(typeof, false)) with @@ -1114,17 +1118,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) } ); + Array.Sort((propsAndFields),{ new 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) } ); + Array.Sort((propsAndFields :> 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.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 - |> List.map (fun p -> (p.Name,(try Some (objL nDepth Precedence.BracketIfTuple (getProperty obj p.Name)) - with _ -> None))) |> 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 00000000000..d3ac670bff1 --- /dev/null +++ b/tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx @@ -0,0 +1,13 @@ +// #Regression #NoMT #FSI +// Public fields did not print. +//val it : PublicField = FSI_0002+PublicField \{X = 2; +// Y = 1;\} +[] +type PublicField = + val X : int + val mutable Y : int + new (x) = { X = x ; Y = 1 } + +let t2 = PublicField(2);; +t2;; +#q;; diff --git a/tests/fsharpqa/Source/InteractiveSession/Misc/env.lst b/tests/fsharpqa/Source/InteractiveSession/Misc/env.lst index 03dcd5eb60c..13803307162 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