Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 29 additions & 21 deletions src/utils/sformat.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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,[||])
Expand All @@ -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 -> "\\\'"
Expand Down Expand Up @@ -827,7 +829,7 @@ namespace Microsoft.FSharp.Text.StructuredFormat
Some (wordL (x.ToString()))
else
// Try the StructuredFormatDisplayAttribute extensibility attribute
match x.GetType().GetCustomAttributes (typeof<StructuredFormatDisplayAttribute>, true) with
match ty.GetCustomAttributes (typeof<StructuredFormatDisplayAttribute>, true) with
| null | [| |] -> None
| res ->
let attr = (res.[0] :?> StructuredFormatDisplayAttribute)
Expand Down Expand Up @@ -862,7 +864,7 @@ namespace Microsoft.FSharp.Text.StructuredFormat
let postText = m.Groups.["post"].Value // Everything after the closing bracket
Copy link
Contributor

@KevinRansom KevinRansom Aug 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up at line 832:
we get x.GetType() again ... I suppose we can remove it and use the ty that we fetched in 827

    let ty = x.GetType()
    if ty.IsGenericType && ty.GetGenericTypeDefinition() = typedefof<Lazy<_>> then
        Some (wordL (x.ToString()))
    else
        // Try the StructuredFormatDisplayAttribute extensibility attribute
        match x.GetType().GetCustomAttributes (typeof<StructuredFormatDisplayAttribute>, true) with

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 ("<StructuredFormatDisplay exception: " + e.Message + ">"))
| Choice1Of2 alternativeObj ->
try
Expand Down Expand Up @@ -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
Expand All @@ -1044,18 +1046,17 @@ namespace Microsoft.FSharp.Text.StructuredFormat

// Format 'set' and 'map' nicely
| _ when
(let ty = obj.GetType()
ty.IsGenericType && (ty.GetGenericTypeDefinition() = typedefof<Map<int,int>>
(ty.IsGenericType && (ty.GetGenericTypeDefinition() = typedefof<Map<int,int>>
|| ty.GetGenericTypeDefinition() = typedefof<Set<int>>) ) ->
let ty = obj.GetType()
let word = if ty.GetGenericTypeDefinition() = typedefof<Map<int,int>> 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<KeyValuePair<int,int>> then
objL depthLim Precedence.BracketIfTuple (v.GetType().GetProperty("Key").GetValue(v, [| |]),
v.GetType().GetProperty("Value").GetValue(v, [| |]))
tyv.IsGenericType &&
tyv.GetGenericTypeDefinition() = typedefof<KeyValuePair<int,int>> 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()
Expand Down Expand Up @@ -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 "<seq>" |> showModeFilter
| _ ->
if showMode = ShowTopLevelBinding && typeUsesSystemObjectToString (obj.GetType()) then
if showMode = ShowTopLevelBinding && typeUsesSystemObjectToString ty then
emptyL
else
countNodes 1
Expand All @@ -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<System.Diagnostics.DebuggerBrowsableAttribute>, false)) with
Expand All @@ -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<PropertyInfo> with member this.Compare(p1,p2) = compare (p1.Name) (p2.Name) } );
Array.Sort((propsAndFields),{ new IComparer<MemberInfo> 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
Expand Down
13 changes: 13 additions & 0 deletions tests/fsharpqa/Source/InteractiveSession/Misc/PublicField.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// #Regression #NoMT #FSI
// Public fields did not print.
//<Expects status="success">val it : PublicField = FSI_0002+PublicField \{X = 2;
// Y = 1;\}</Expects>
[<Struct>]
type PublicField =
val X : int
val mutable Y : int
new (x) = { X = x ; Y = 1 }

let t2 = PublicField(2);;
t2;;
#q;;
4 changes: 3 additions & 1 deletion tests/fsharpqa/Source/InteractiveSession/Misc/env.lst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down