From d25b3a8bc86a5a2175d76084c7022cda7ea6bd03 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 13 Jun 2023 09:24:00 +0200 Subject: [PATCH] Return F# signature text for C# override. --- src/Compiler/Checking/NicePrint.fs | 13 ++++- src/Compiler/Checking/NicePrint.fsi | 3 ++ src/Compiler/Symbols/Symbols.fs | 4 +- .../Signatures/TypeTests.fs | 54 ++++++++++++++++++- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs index da4caaf7f2e..8ed4b5d9d68 100644 --- a/src/Compiler/Checking/NicePrint.fs +++ b/src/Compiler/Checking/NicePrint.fs @@ -1533,8 +1533,13 @@ module InfoMemberPrinting = WordL.keywordNew else let idL = ConvertValLogicalNameToDisplayLayout false (tagMethod >> tagNavArbValRef minfo.ArbitraryValRef >> wordL) minfo.LogicalName - WordL.keywordMember ^^ - PrintTypes.layoutTyparDecls denv idL true minfo.FormalMethodTypars + let keywordLayout = + match minfo with + | ILMeth(ilMethInfo = ilMethInfo) when ilMethInfo.IsAbstract -> + WordL.keywordOverride + | _ -> WordL.keywordMember + + keywordLayout ^^ PrintTypes.layoutTyparDecls denv idL true minfo.FormalMethodTypars let layout = layout ^^ (nameL |> addColonL) let layout = layoutXmlDocOfMethInfo denv infoReader minfo layout @@ -2617,6 +2622,10 @@ let prettyLayoutOfPropInfoFreeStyle g amap m denv d = let stringOfMethInfo infoReader m denv minfo = buildString (fun buf -> InfoMemberPrinting.formatMethInfoToBufferFreeStyle infoReader m denv buf minfo) +let stringOfMethInfoFSharpStyle infoReader m denv minfo = + InfoMemberPrinting.layoutMethInfoFSharpStyle infoReader m denv minfo + |> showL + /// Convert MethInfos to lines separated by newline including a newline as the first character let multiLineStringOfMethInfos infoReader m denv minfos = minfos diff --git a/src/Compiler/Checking/NicePrint.fsi b/src/Compiler/Checking/NicePrint.fsi index ffe6aa7ea84..84dabb2c95b 100644 --- a/src/Compiler/Checking/NicePrint.fsi +++ b/src/Compiler/Checking/NicePrint.fsi @@ -81,6 +81,9 @@ val prettyLayoutOfPropInfoFreeStyle: val stringOfMethInfo: infoReader: InfoReader -> m: range -> denv: DisplayEnv -> minfo: MethInfo -> string +/// Convert a MethInfo to a F# signature +val stringOfMethInfoFSharpStyle: infoReader: InfoReader -> m: range -> denv: DisplayEnv -> minfo: MethInfo -> string + val multiLineStringOfMethInfos: infoReader: InfoReader -> m: range -> denv: DisplayEnv -> minfos: MethInfo list -> string diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index ad7af21e718..615648dd9c4 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -2359,10 +2359,10 @@ type FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) = checkIsResolved() let displayEnv = { displayContext.Contents cenv.g with includeStaticParametersInTypeNames = true } - let stringValOfMethInfo methInfo = + let stringValOfMethInfo (methInfo: MethInfo) = match methInfo with | FSMeth(valRef = vref) -> NicePrint.stringValOrMember displayEnv cenv.infoReader vref - | _ -> NicePrint.stringOfMethInfo cenv.infoReader m displayEnv methInfo + | _ -> NicePrint.stringOfMethInfoFSharpStyle cenv.infoReader m displayEnv methInfo let stringValOfPropInfo (p: PropInfo) = let t = p.GetPropertyType(cenv.amap, m ) |> NicePrint.layoutType displayEnv |> LayoutRender.showL diff --git a/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs b/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs index a4f18d4076f..cd637449500 100644 --- a/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Signatures/TypeTests.fs @@ -1,5 +1,6 @@ module Signatures.TypeTests +open FSharp.Compiler.Symbols open Xunit open FsUnit open FSharp.Test.Compiler @@ -131,4 +132,55 @@ module Extensions type System.Collections.Concurrent.ConcurrentDictionary<'key,'value> with member TryFind: key: 'key -> 'value option""" - \ No newline at end of file + +[] +let ``ValText for C# abstract member override`` () = + let csharp = CSharp """ +namespace CSharp.Library +{ + using System; + using System.Globalization; + using System.Runtime.CompilerServices; + using System.Diagnostics.CodeAnalysis; + + public abstract class JsonConverter + { + public abstract void WriteJson(object writer, object? value, object serializer); + public abstract object? ReadJson(object reader, Type objectType, object? existingValue, object serializer); + public abstract bool CanConvert(Type objectType); + public virtual bool CanRead => true; + public virtual bool CanWrite => true; + } +} +""" + + FSharp """ +module F + +open CSharp.Library + +[] +type EConverter () = + inherit JsonConverter () + + override this.WriteJson(writer, value, serializer) = failwith "todo" + override this.ReadJson(reader, objectType, existingValue, serializer) = failwith "todo" + override this.CanConvert(objectType) = failwith "todo" + override this.CanRead = true +""" + |> withReferences [ csharp ] + |> typecheckResults + |> fun results -> + let writeJsonSymbolUse = results.GetSymbolUseAtLocation(10, 27, " override this.WriteJson(writer, value, serializer) = failwith \"todo\"", [ "WriteJson" ]).Value + match writeJsonSymbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as mfv -> + let valText = mfv.GetValSignatureText(writeJsonSymbolUse.DisplayContext, writeJsonSymbolUse.Range).Value + Assert.Equal("override WriteJson: writer: obj * value: obj * serializer: obj -> unit", valText) + | _ -> () + + let canReadSymbolUse = results.GetSymbolUseAtLocation(13, 25, " override this.CanRead = true", [ "CanRead" ]).Value + match canReadSymbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as mfv -> + let valText = mfv.GetValSignatureText(canReadSymbolUse.DisplayContext, canReadSymbolUse.Range).Value + Assert.Equal("override CanRead: bool", valText) + | _ -> ()