Skip to content

Commit 7409333

Browse files
saulKevinRansom
authored andcommitted
Improve fsi printing/%A formatting (#7710)
* Improved printing * Fix SynAccess ToString * Fixup tests * Disable tests that depend on updated fsharp.core Co-authored-by: Kevin Ransom (msft) <codecutter.fsharp@hotmail.com>
1 parent 5e231fd commit 7409333

File tree

5 files changed

+83
-40
lines changed

5 files changed

+83
-40
lines changed

fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@
636636
<Compile Include="$(FSharpSourcesRoot)\fsharp\service\ExternalSymbol.fs">
637637
<Link>Service/ExternalSymbol.fs</Link>
638638
</Compile>
639-
<Compile Include="$(FSharpSourcesRoot)\fsharp\service\QuickParse.fsi">
639+
<Compile Include="$(FSharpSourcesRoot)\fsharp\service\QuickParse.fsi">
640640
<Link>Service/QuickParse.fsi</Link>
641641
</Compile>
642642
<Compile Include="$(FSharpSourcesRoot)\fsharp\service\QuickParse.fs">

src/fsharp/FSharp.Core/printf.fs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,9 +1059,11 @@ module internal PrintfImpl =
10591059

10601060
static member GenericToStringCore(v: 'T, opts: Microsoft.FSharp.Text.StructuredPrintfImpl.FormatOptions, bindingFlags) =
10611061
// printfn %0A is considered to mean 'print width zero'
1062-
match box v with
1063-
| null -> "<null>"
1064-
| _ -> Microsoft.FSharp.Text.StructuredPrintfImpl.Display.anyToStringForPrintf opts bindingFlags (v, v.GetType())
1062+
match box v with
1063+
| null ->
1064+
Microsoft.FSharp.Text.StructuredPrintfImpl.Display.anyToStringForPrintf opts bindingFlags (v, typeof<'T>)
1065+
| _ ->
1066+
Microsoft.FSharp.Text.StructuredPrintfImpl.Display.anyToStringForPrintf opts bindingFlags (v, v.GetType())
10651067

10661068
static member GenericToString<'T>(spec: FormatSpecifier) =
10671069
let bindingFlags =

src/fsharp/ast.fs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,12 @@ type SynAccess =
330330
| Internal
331331
| Private
332332

333+
override this.ToString () =
334+
match this with
335+
| Public -> "Public"
336+
| Internal -> "Internal"
337+
| Private -> "Private"
338+
333339
type SequencePointInfoForTarget =
334340
| SequencePointAtTarget
335341
| SuppressSequencePointAtTarget

src/utils/sformat.fs

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -366,17 +366,27 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
366366
(let cases = FSharpType.GetUnionCases ty
367367
cases.Length > 0 && equivHeadTypes (typedefof<list<_>>) cases.[0].DeclaringType)
368368

369+
[<RequireQualifiedAccess; StructuralComparison; StructuralEquality>]
370+
type TupleType =
371+
| Value
372+
| Reference
373+
369374
[<NoEquality; NoComparison>]
370375
type ValueInfo =
371-
| TupleValue of (obj * Type) list
376+
| TupleValue of TupleType * (obj * Type) list
372377
| FunctionClosureValue of System.Type
373378
| RecordValue of (string * obj * Type) list
374-
| ConstructorValue of string * (string * (obj * Type)) list
379+
| ConstructorValue of declaringType: Type option * string * (string * (obj * Type)) list
375380
| ExceptionValue of System.Type * (string * (obj * Type)) list
376381
| UnitValue
377382
| ObjectValue of obj
378383

379-
module Value =
384+
module Value =
385+
386+
// Returns true if a given type has the RequireQualifiedAccess attribute
387+
let private requiresQualifiedAccess (declaringType:Type) =
388+
let rqaAttr = declaringType.GetCustomAttribute(typeof<RequireQualifiedAccessAttribute>, false)
389+
isNull rqaAttr |> not
380390

381391
// Analyze an object to see if it the representation
382392
// of an F# value.
@@ -393,7 +403,11 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
393403

394404
if FSharpType.IsTuple reprty then
395405
let tyArgs = FSharpType.GetTupleElements(reprty)
396-
TupleValue (FSharpValue.GetTupleFields obj |> Array.mapi (fun i v -> (v, tyArgs.[i])) |> Array.toList)
406+
let fields = FSharpValue.GetTupleFields obj |> Array.mapi (fun i v -> (v, tyArgs.[i])) |> Array.toList
407+
let tupleType =
408+
if reprty.Name.StartsWith "ValueTuple" then TupleType.Value
409+
else TupleType.Reference
410+
TupleValue (tupleType, fields)
397411
elif FSharpType.IsFunction reprty then
398412
FunctionClosureValue reprty
399413

@@ -406,7 +420,10 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
406420
let tag,vals = FSharpValue.GetUnionFields (obj,reprty,bindingFlags)
407421
let props = tag.GetFields()
408422
let pvals = (props,vals) ||> Array.map2 (fun prop v -> prop.Name,(v, prop.PropertyType))
409-
ConstructorValue(tag.Name, Array.toList pvals)
423+
let declaringType =
424+
if requiresQualifiedAccess tag.DeclaringType then Some tag.DeclaringType
425+
else None
426+
ConstructorValue(declaringType, tag.Name, Array.toList pvals)
410427
elif FSharpType.IsExceptionRepresentation(reprty,bindingFlags) then
411428
let props = FSharpType.GetExceptionFields(reprty,bindingFlags)
412429
let vals = FSharpValue.GetExceptionFields(obj,bindingFlags)
@@ -426,16 +443,19 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
426443
let obj = (box x)
427444
match obj with
428445
| null ->
429-
let isNullaryUnion =
430-
match ty.GetCustomAttributes(typeof<CompilationRepresentationAttribute>, false) with
431-
| [|:? CompilationRepresentationAttribute as attr|] ->
446+
let isNullaryUnion =
447+
match ty.GetCustomAttributes(typeof<CompilationRepresentationAttribute>, false) with
448+
| [|:? CompilationRepresentationAttribute as attr|] ->
432449
(attr.Flags &&& CompilationRepresentationFlags.UseNullAsTrueValue) = CompilationRepresentationFlags.UseNullAsTrueValue
433-
| _ -> false
434-
if isNullaryUnion then
435-
let nullaryCase = FSharpType.GetUnionCases ty |> Array.filter (fun uc -> uc.GetFields().Length = 0) |> Array.item 0
436-
ConstructorValue(nullaryCase.Name, [])
437-
elif isUnitType ty then UnitValue
438-
else ObjectValue(obj)
450+
| _ -> false
451+
if isNullaryUnion then
452+
let nullaryCase = FSharpType.GetUnionCases ty |> Array.filter (fun uc -> uc.GetFields().Length = 0) |> Array.item 0
453+
let declaringType =
454+
if requiresQualifiedAccess ty then Some ty
455+
else None
456+
ConstructorValue(declaringType, nullaryCase.Name, [])
457+
elif isUnitType ty then UnitValue
458+
else ObjectValue(obj)
439459
| _ ->
440460
GetValueInfoOfObject bindingFlags (obj)
441461

@@ -700,11 +720,11 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
700720
| null -> None
701721
| _ ->
702722
match getValueInfo bindingFlags (x, ty) with
703-
| ConstructorValue ("Cons",recd) -> Some (unpackCons recd)
704-
| ConstructorValue ("Empty",[]) -> None
723+
| ConstructorValue (_,"Cons",recd) -> Some (unpackCons recd)
724+
| ConstructorValue (_,"Empty",[]) -> None
705725
| _ -> failwith "List value had unexpected ValueInfo"
706726

707-
let compactCommaListL xs = sepListL (sepL Literals.comma) xs // compact, no spaces around ","
727+
let structL = wordL (tagKeyword "struct")
708728
let nullL = wordL (tagKeyword "null")
709729
let measureL = wordL (tagPunctuation "()")
710730

@@ -967,25 +987,28 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
967987
// tuples up args to UnionConstruction or ExceptionConstructor. no node count.
968988
match recd with
969989
| [(_,x)] -> objL depthLim Precedence.BracketIfTupleOrNotAtomic x
970-
| txs -> leftL Literals.leftParen ^^ compactCommaListL (List.map (snd >> objL depthLim Precedence.BracketIfTuple) txs) ^^ rightL Literals.rightParen
990+
| txs -> leftL Literals.leftParen ^^ commaListL (List.map (snd >> objL depthLim Precedence.BracketIfTuple) txs) ^^ rightL Literals.rightParen
971991

972992
and bracketIfL b basicL =
973993
if b then (leftL Literals.leftParen) ^^ basicL ^^ (rightL Literals.rightParen) else basicL
974994

975995
and reprL showMode depthLim prec repr x (* x could be null *) =
976996
let showModeFilter lay = match showMode with ShowAll -> lay | ShowTopLevelBinding -> emptyL
977-
match repr with
978-
| TupleValue vals ->
997+
match repr with
998+
| TupleValue (tupleType, vals) ->
979999
let basicL = sepListL (rightL Literals.comma) (List.map (objL depthLim Precedence.BracketIfTuple ) vals)
980-
bracketIfL (prec <= Precedence.BracketIfTuple) basicL
1000+
let fields = bracketIfL (prec <= Precedence.BracketIfTuple) basicL
1001+
match tupleType with
1002+
| TupleType.Value -> structL ^^ fields
1003+
| TupleType.Reference -> fields
9811004

9821005
| RecordValue items ->
9831006
let itemL (name,x,ty) =
9841007
countNodes 1 // record labels are counted as nodes. [REVIEW: discussion under 4090].
9851008
(tagRecordField name,objL depthLim Precedence.BracketIfTuple (x, ty))
9861009
makeRecordL (List.map itemL items)
9871010

988-
| ConstructorValue (constr,recd) when // x is List<T>. Note: "null" is never a valid list value.
1011+
| ConstructorValue (_,constr,recd) when // x is List<T>. Note: "null" is never a valid list value.
9891012
x<>null && isListType (x.GetType()) ->
9901013
match constr with
9911014
| "Cons" ->
@@ -997,13 +1020,17 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
9971020
countNodes 1
9981021
wordL (tagPunctuation "[]")
9991022

1000-
| ConstructorValue(nm,[]) ->
1023+
| ConstructorValue(declaringType,nm,recd) ->
10011024
countNodes 1
1002-
(wordL (tagMethod nm))
1003-
1004-
| ConstructorValue(nm,recd) ->
1005-
countNodes 1 // e.g. Some (Some (Some (Some 2))) should count for 5
1006-
(wordL (tagMethod nm) --- recdAtomicTupleL depthLim recd) |> bracketIfL (prec <= Precedence.BracketIfTupleOrNotAtomic)
1025+
let caseName =
1026+
match declaringType with
1027+
| None ->
1028+
wordL (tagMethod nm)
1029+
| Some declaringType ->
1030+
wordL (tagClass declaringType.Name) ^^ sepL (tagPunctuation ".") ^^ wordL (tagMethod nm)
1031+
match recd with
1032+
| [] -> caseName
1033+
| recd -> (caseName --- recdAtomicTupleL depthLim recd) |> bracketIfL (prec <= Precedence.BracketIfTupleOrNotAtomic)
10071034

10081035
| ExceptionValue(ty,recd) ->
10091036
countNodes 1
@@ -1019,7 +1046,12 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
10191046

10201047
| ObjectValue(obj) ->
10211048
match obj with
1022-
| null -> (countNodes 1; nullL)
1049+
| null ->
1050+
countNodes 1
1051+
// If this is the root element, wrap the null with angle brackets
1052+
if depthLim = opts.PrintDepth - 1 then
1053+
wordL (tagText "<null>")
1054+
else nullL
10231055
| _ ->
10241056
let ty = obj.GetType()
10251057
match obj with

tests/service/ExprTests.fs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,11 @@ let test{0}ToStringOperator (e1:{1}) = string e1
637637
638638
"""
639639

640-
//<@ let x = Some(3) in x.IsSome @>
641640
[<Test>]
641+
// FCS Has a problem with these tests because of FSharp Core versions.
642+
#if !COMPILER_SERVICE_AS_DLL
643+
[<Ignore("SKIPPED: FSharp.Core nuget package needs to be updated before this test can be re-enabled")>]
644+
#endif
642645
let ``Test Unoptimized Declarations Project1`` () =
643646
let wholeProjectResults = exprChecker.ParseAndCheckProject(Project1.options) |> Async.RunSynchronously
644647

@@ -711,7 +714,7 @@ let ``Test Unoptimized Declarations Project1`` () =
711714
"member CurriedMethod(x) (a1,b1) (a2,b2) = 1 @ (107,63--107,64)";
712715
"let testFunctionThatCallsMultiArgMethods(unitVar0) = let m: M.MultiArgMethods = new MultiArgMethods(3,4) in Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (m.Method(7,8),fun tupledArg -> let arg00: Microsoft.FSharp.Core.int = tupledArg.Item0 in let arg01: Microsoft.FSharp.Core.int = tupledArg.Item1 in fun tupledArg -> let arg10: Microsoft.FSharp.Core.int = tupledArg.Item0 in let arg11: Microsoft.FSharp.Core.int = tupledArg.Item1 in m.CurriedMethod(arg00,arg01,arg10,arg11) (9,10) (11,12)) @ (110,8--110,9)";
713716
"let testFunctionThatUsesUnitsOfMeasure(x) (y) = Operators.op_Addition<Microsoft.FSharp.Core.float<'u>,Microsoft.FSharp.Core.float<'u>,Microsoft.FSharp.Core.float<'u>> (x,y) @ (122,70--122,75)";
714-
"let testFunctionThatUsesAddressesAndByrefs(x) = let mutable w: Microsoft.FSharp.Core.int = 4 in let y1: Microsoft.FSharp.Core.byref<Microsoft.FSharp.Core.int> = x in let y2: Microsoft.FSharp.Core.byref<Microsoft.FSharp.Core.int> = &w in let arr: Microsoft.FSharp.Core.int Microsoft.FSharp.Core.[] = [|3; 4|] in let r: Microsoft.FSharp.Core.int Microsoft.FSharp.Core.ref = Operators.Ref<Microsoft.FSharp.Core.int> (3) in let y3: Microsoft.FSharp.Core.byref<Microsoft.FSharp.Core.int> = [I_ldelema (NormalAddress,false,ILArrayShapeFIX,!0)](arr,0) in let y4: Microsoft.FSharp.Core.byref<Microsoft.FSharp.Core.int> = &r.contents in let z: Microsoft.FSharp.Core.int = Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (x,y1),y2),y3) in (w <- 3; (x <- 4; (y2 <- 4; (y3 <- 5; Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (z,x),y1),y2),y3),y4),IntrinsicFunctions.GetArray<Microsoft.FSharp.Core.int> (arr,0)),r.contents))))) @ (125,16--125,17)";
717+
"let testFunctionThatUsesAddressesAndByrefs(x) = let mutable w: Microsoft.FSharp.Core.int = 4 in let y1: Microsoft.FSharp.Core.byref<Microsoft.FSharp.Core.int> = x in let y2: Microsoft.FSharp.Core.byref<Microsoft.FSharp.Core.int> = &w in let arr: Microsoft.FSharp.Core.int Microsoft.FSharp.Core.[] = [|3; 4|] in let r: Microsoft.FSharp.Core.int Microsoft.FSharp.Core.ref = Operators.Ref<Microsoft.FSharp.Core.int> (3) in let y3: Microsoft.FSharp.Core.byref<Microsoft.FSharp.Core.int> = [I_ldelema (NormalAddress, false, ILArrayShapeFIX, !0)](arr,0) in let y4: Microsoft.FSharp.Core.byref<Microsoft.FSharp.Core.int> = &r.contents in let z: Microsoft.FSharp.Core.int = Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (x,y1),y2),y3) in (w <- 3; (x <- 4; (y2 <- 4; (y3 <- 5; Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (z,x),y1),y2),y3),y4),IntrinsicFunctions.GetArray<Microsoft.FSharp.Core.int> (arr,0)),r.contents))))) @ (125,16--125,17)";
715718
"let testFunctionThatUsesStructs1(dt) = dt.AddDays(3) @ (139,57--139,72)";
716719
"let testFunctionThatUsesStructs2(unitVar0) = let dt1: System.DateTime = DateTime.get_Now () in let mutable dt2: System.DateTime = DateTime.get_Now () in let dt3: System.TimeSpan = Operators.op_Subtraction<System.DateTime,System.DateTime,System.TimeSpan> (dt1,dt2) in let dt4: System.DateTime = dt1.AddDays(3) in let dt5: Microsoft.FSharp.Core.int = dt1.get_Millisecond() in let dt6: Microsoft.FSharp.Core.byref<System.DateTime> = &dt2 in let dt7: System.TimeSpan = Operators.op_Subtraction<System.DateTime,System.DateTime,System.TimeSpan> (dt6,dt4) in dt7 @ (142,7--142,10)";
717720
"let testFunctionThatUsesWhileLoop(unitVar0) = let mutable x: Microsoft.FSharp.Core.int = 1 in (while Operators.op_LessThan<Microsoft.FSharp.Core.int> (x,100) do x <- Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (x,1) done; x) @ (152,15--152,16)";
@@ -745,9 +748,9 @@ let ``Test Unoptimized Declarations Project1`` () =
745748
"type LetLambda";
746749
"let f = ((); fun a -> fun b -> Operators.op_Addition<Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (a,b)) @ (246,8--247,24)";
747750
"let letLambdaRes = Operators.op_PipeRight<(Microsoft.FSharp.Core.int * Microsoft.FSharp.Core.int) Microsoft.FSharp.Collections.list,Microsoft.FSharp.Core.int Microsoft.FSharp.Collections.list> (Cons((1,2),Empty()),let mapping: Microsoft.FSharp.Core.int * Microsoft.FSharp.Core.int -> Microsoft.FSharp.Core.int = fun tupledArg -> let a: Microsoft.FSharp.Core.int = tupledArg.Item0 in let b: Microsoft.FSharp.Core.int = tupledArg.Item1 in (LetLambda.f () a) b in fun list -> ListModule.Map<Microsoft.FSharp.Core.int * Microsoft.FSharp.Core.int,Microsoft.FSharp.Core.int> (mapping,list)) @ (249,19--249,71)";
748-
"let anonRecd = {X = 1; Y = 2} @ (251,15--251,33)"
751+
"let anonRecd = {X = 1; Y = 2} @ (251,15--251,33)";
749752
"let anonRecdGet = (M.anonRecd ().X,M.anonRecd ().Y) @ (252,19--252,41)"
750-
]
753+
]
751754

752755
let expected2 = [
753756
"type N"; "type IntAbbrev"; "let bool2 = False @ (6,12--6,17)";
@@ -780,10 +783,10 @@ let ``Test Unoptimized Declarations Project1`` () =
780783

781784

782785
[<Test>]
783-
//#if NETCOREAPP
784-
//[<Ignore("SKIPPED: need to check if these tests can be enabled for .NET Core testing of FSharp.Compiler.Service")>]
785-
//#endif
786+
// FCS Has a problem with these tests because of FSharp Core versions
787+
#if !COMPILER_SERVICE_AS_DLL
786788
[<Ignore("SKIPPED: FSharp.Core nuget package needs to be updated before this test can be re-enabled")>]
789+
#endif
787790
let ``Test Optimized Declarations Project1`` () =
788791
let wholeProjectResults = exprChecker.ParseAndCheckProject(Project1.options) |> Async.RunSynchronously
789792

0 commit comments

Comments
 (0)