From 4e8edb3d95a31951534f7be381dfc4ffa7a842b4 Mon Sep 17 00:00:00 2001 From: Petr Date: Wed, 23 Nov 2022 16:12:48 +0100 Subject: [PATCH 1/6] Make inline type hints less intrusive --- .../Service/ServiceInterfaceStubGenerator.fs | 2 +- src/Compiler/Symbols/Symbols.fs | 2 +- src/Compiler/Symbols/Symbols.fsi | 2 +- .../src/FSharp.Editor/Hints/InlineTypeHints.fs | 7 ++++++- .../FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs | 12 ++++++++++++ 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Compiler/Service/ServiceInterfaceStubGenerator.fs b/src/Compiler/Service/ServiceInterfaceStubGenerator.fs index 55ff01779f..88dd690c3c 100644 --- a/src/Compiler/Service/ServiceInterfaceStubGenerator.fs +++ b/src/Compiler/Service/ServiceInterfaceStubGenerator.fs @@ -188,7 +188,7 @@ module InterfaceStubGenerator = Some(List.rev revd.Tail, revd.Head) let internal getTypeParameterName (typar: FSharpGenericParameter) = - (if typar.IsSolveAtCompileTime then "^" else "'") + typar.Name + (if typar.IsSolvedAtCompileTime then "^" else "'") + typar.Name let internal bracket (str: string) = if str.Contains(" ") then "(" + str + ")" else str diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index 499654b029..6fb54a1c36 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -1352,7 +1352,7 @@ type FSharpGenericParameter(cenv, v:Typar) = member _.ElaboratedXmlDoc = v.XmlDoc |> makeElaboratedXmlDoc - member _.IsSolveAtCompileTime = (v.StaticReq = TyparStaticReq.HeadType) + member _.IsSolvedAtCompileTime = (v.StaticReq = TyparStaticReq.HeadType) override _.Attributes = // INCOMPLETENESS: If the type parameter comes from .NET then the .NET metadata for the type parameter diff --git a/src/Compiler/Symbols/Symbols.fsi b/src/Compiler/Symbols/Symbols.fsi index 8a38e2cb03..d0bf0b6dfc 100644 --- a/src/Compiler/Symbols/Symbols.fsi +++ b/src/Compiler/Symbols/Symbols.fsi @@ -598,7 +598,7 @@ type FSharpGenericParameter = member XmlDoc: FSharpXmlDoc /// Indicates if this is a statically resolved type variable - member IsSolveAtCompileTime: bool + member IsSolvedAtCompileTime: bool /// Indicates if this is a compiler generated type parameter member IsCompilerGenerated: bool diff --git a/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs b/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs index 09566e0514..c6165cd185 100644 --- a/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs +++ b/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs @@ -34,7 +34,11 @@ module InlineTypeHints = (parseFileResults: FSharpParseFileResults) (symbol: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) = - + + let isSolved = + symbol.GenericParameters + |> Seq.forall (fun p -> p.IsSolvedAtCompileTime) + let isNotAnnotatedManually = not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) @@ -46,6 +50,7 @@ module InlineTypeHints = not symbol.IsConstructorThisValue symbol.IsValue // we'll be adding other stuff gradually here + && isSolved && isNotAnnotatedManually && isNotAfterDot && isNotTypeAlias diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs index a8445ede5e..e4da7a2e7f 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs @@ -183,3 +183,15 @@ let zip4 (l1: 'a list) (l2: 'b list) (l3: 'c list) (l4: 'd list) = let actual = getTypeHints document CollectionAssert.AreEquivalent(expected, actual) + + [] + let ``Hints are not shown for unfinished expressions`` () = + let code = + """ +let x +""" + let document = getFsDocument code + + let result = getTypeHints document + + Assert.IsEmpty(result) From e4415f61292c845e7820bf6157c24077537daeac Mon Sep 17 00:00:00 2001 From: Petr Date: Thu, 24 Nov 2022 19:42:00 +0100 Subject: [PATCH 2/6] Update --- .../FSharp.CompilerService.SurfaceArea.netstandard.expected | 2 +- tests/service/ExprTests.fs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index 4fbe51be8a..46fd24d709 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -4734,7 +4734,7 @@ FSharp.Compiler.Symbols.FSharpGenericParameter FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean Equals(System.Object) FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean IsCompilerGenerated FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean IsMeasure -FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean IsSolveAtCompileTime +FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean IsSolvedAtCompileTime FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean get_IsCompilerGenerated() FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean get_IsMeasure() FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean get_IsSolveAtCompileTime() diff --git a/tests/service/ExprTests.fs b/tests/service/ExprTests.fs index 02a62ba5b9..ea51fa3c1b 100644 --- a/tests/service/ExprTests.fs +++ b/tests/service/ExprTests.fs @@ -263,7 +263,7 @@ module internal Utils = let printGenericParameter (p: FSharpGenericParameter) = let name = if p.Name.StartsWith("?", StringComparison.Ordinal) then "_" - elif p.IsSolveAtCompileTime then "^" + p.Name + elif p.IsSolvedAtCompileTime then "^" + p.Name else "'" + p.Name let constraints = p.Constraints |> Seq.choose (printGenericConstraint name) |> List.ofSeq From 7abc3584a7481b3c39d9d00227af6ea8bf778d0a Mon Sep 17 00:00:00 2001 From: Petr Date: Thu, 24 Nov 2022 20:35:23 +0100 Subject: [PATCH 3/6] Reverting the breaking change --- src/Compiler/Service/ServiceInterfaceStubGenerator.fs | 2 +- src/Compiler/Symbols/Symbols.fs | 2 +- src/Compiler/Symbols/Symbols.fsi | 2 +- .../FSharp.CompilerService.SurfaceArea.netstandard.expected | 2 +- tests/service/ExprTests.fs | 2 +- vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Compiler/Service/ServiceInterfaceStubGenerator.fs b/src/Compiler/Service/ServiceInterfaceStubGenerator.fs index 88dd690c3c..55ff01779f 100644 --- a/src/Compiler/Service/ServiceInterfaceStubGenerator.fs +++ b/src/Compiler/Service/ServiceInterfaceStubGenerator.fs @@ -188,7 +188,7 @@ module InterfaceStubGenerator = Some(List.rev revd.Tail, revd.Head) let internal getTypeParameterName (typar: FSharpGenericParameter) = - (if typar.IsSolvedAtCompileTime then "^" else "'") + typar.Name + (if typar.IsSolveAtCompileTime then "^" else "'") + typar.Name let internal bracket (str: string) = if str.Contains(" ") then "(" + str + ")" else str diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index 6fb54a1c36..499654b029 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -1352,7 +1352,7 @@ type FSharpGenericParameter(cenv, v:Typar) = member _.ElaboratedXmlDoc = v.XmlDoc |> makeElaboratedXmlDoc - member _.IsSolvedAtCompileTime = (v.StaticReq = TyparStaticReq.HeadType) + member _.IsSolveAtCompileTime = (v.StaticReq = TyparStaticReq.HeadType) override _.Attributes = // INCOMPLETENESS: If the type parameter comes from .NET then the .NET metadata for the type parameter diff --git a/src/Compiler/Symbols/Symbols.fsi b/src/Compiler/Symbols/Symbols.fsi index d0bf0b6dfc..8a38e2cb03 100644 --- a/src/Compiler/Symbols/Symbols.fsi +++ b/src/Compiler/Symbols/Symbols.fsi @@ -598,7 +598,7 @@ type FSharpGenericParameter = member XmlDoc: FSharpXmlDoc /// Indicates if this is a statically resolved type variable - member IsSolvedAtCompileTime: bool + member IsSolveAtCompileTime: bool /// Indicates if this is a compiler generated type parameter member IsCompilerGenerated: bool diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index 46fd24d709..4fbe51be8a 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -4734,7 +4734,7 @@ FSharp.Compiler.Symbols.FSharpGenericParameter FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean Equals(System.Object) FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean IsCompilerGenerated FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean IsMeasure -FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean IsSolvedAtCompileTime +FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean IsSolveAtCompileTime FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean get_IsCompilerGenerated() FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean get_IsMeasure() FSharp.Compiler.Symbols.FSharpGenericParameter: Boolean get_IsSolveAtCompileTime() diff --git a/tests/service/ExprTests.fs b/tests/service/ExprTests.fs index ea51fa3c1b..02a62ba5b9 100644 --- a/tests/service/ExprTests.fs +++ b/tests/service/ExprTests.fs @@ -263,7 +263,7 @@ module internal Utils = let printGenericParameter (p: FSharpGenericParameter) = let name = if p.Name.StartsWith("?", StringComparison.Ordinal) then "_" - elif p.IsSolvedAtCompileTime then "^" + p.Name + elif p.IsSolveAtCompileTime then "^" + p.Name else "'" + p.Name let constraints = p.Constraints |> Seq.choose (printGenericConstraint name) |> List.ofSeq diff --git a/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs b/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs index c6165cd185..e63a907975 100644 --- a/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs +++ b/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs @@ -37,7 +37,7 @@ module InlineTypeHints = let isSolved = symbol.GenericParameters - |> Seq.forall (fun p -> p.IsSolvedAtCompileTime) + |> Seq.forall (fun p -> p.IsSolveAtCompileTime) let isNotAnnotatedManually = not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) From c4d01127b806b1c2ef4532c27caab7b4a50721c4 Mon Sep 17 00:00:00 2001 From: Petr Date: Fri, 25 Nov 2022 13:51:15 +0100 Subject: [PATCH 4/6] IWSAM --- .../Hints/InlineTypeHintTests.fs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs index e4da7a2e7f..0c9bf96752 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs @@ -195,3 +195,27 @@ let x let result = getTypeHints document Assert.IsEmpty(result) + + [] + let ``Hints are shown for IWSAM`` () = + let code = + """ +type IAddition<'T when 'T :> IAddition<'T>> = + static abstract op_Addition: 'T * 'T -> 'T + +type Number<'T when IAddition<'T>>(value: 'T) = + member _.Value with get() = value + interface IAddition> with + static member op_Addition(a, b) = Number(a.Value + b.Value) +""" + let document = getFsDocument code + + let expected = + [ + { Content = ": Number<'T>"; Location = (7, 36) } + { Content = ": Number<'T>"; Location = (7, 39) } + ] + + let actual = getTypeHints document + + CollectionAssert.AreEquivalent(expected, actual) From 898f0605026937dbae61b4ad4dd294a25b1e6a34 Mon Sep 17 00:00:00 2001 From: Petr Date: Mon, 28 Nov 2022 17:44:55 +0100 Subject: [PATCH 5/6] update --- .../src/FSharp.Editor/Hints/InlineTypeHints.fs | 13 +++++++++++-- .../Hints/InlineTypeHintTests.fs | 12 ++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs b/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs index e63a907975..1018cd1305 100644 --- a/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs +++ b/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs @@ -36,8 +36,17 @@ module InlineTypeHints = (symbolUse: FSharpSymbolUse) = let isSolved = - symbol.GenericParameters - |> Seq.forall (fun p -> p.IsSolveAtCompileTime) + let case1 = + if symbol.GenericParameters |> Seq.isEmpty |> not + then symbol.GenericParameters |> Seq.forall (fun p -> p.IsSolveAtCompileTime) + else true + + let case2 = + if symbol.FullType.IsGenericParameter + then symbol.FullType.GenericParameter.DisplayNameCore <> "?" + else true + + case1 && case2 let isNotAnnotatedManually = not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs index 0c9bf96752..67263a593a 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs @@ -196,6 +196,18 @@ let x Assert.IsEmpty(result) + [] + let ``Hints are not shown for unsolved types in for expressions`` () = + let code = + """ +let _ = [ for x ] +""" + let document = getFsDocument code + + let result = getTypeHints document + + Assert.IsEmpty(result) + [] let ``Hints are shown for IWSAM`` () = let code = From 7dc65ab3c01d7043258ace6430768a5854521965 Mon Sep 17 00:00:00 2001 From: Petr Date: Mon, 28 Nov 2022 18:04:01 +0100 Subject: [PATCH 6/6] extra tests --- .../FSharp.Editor/Hints/InlineTypeHints.fs | 24 ++++++++----------- .../Hints/InlineTypeHintTests.fs | 18 +++++++++++++- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs b/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs index 1018cd1305..402eddbaef 100644 --- a/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs +++ b/vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs @@ -30,24 +30,20 @@ module InlineTypeHints = Parts = getHintParts symbol symbolUse } + let private isSolved (symbol: FSharpMemberOrFunctionOrValue) = + if symbol.GenericParameters.Count > 0 + then symbol.GenericParameters |> Seq.forall (fun p -> p.IsSolveAtCompileTime) + + elif symbol.FullType.IsGenericParameter + then symbol.FullType.GenericParameter.DisplayNameCore <> "?" + + else true + let isValidForHint (parseFileResults: FSharpParseFileResults) (symbol: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) = - let isSolved = - let case1 = - if symbol.GenericParameters |> Seq.isEmpty |> not - then symbol.GenericParameters |> Seq.forall (fun p -> p.IsSolveAtCompileTime) - else true - - let case2 = - if symbol.FullType.IsGenericParameter - then symbol.FullType.GenericParameter.DisplayNameCore <> "?" - else true - - case1 && case2 - let isNotAnnotatedManually = not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) @@ -59,7 +55,7 @@ module InlineTypeHints = not symbol.IsConstructorThisValue symbol.IsValue // we'll be adding other stuff gradually here - && isSolved + && isSolved symbol && isNotAnnotatedManually && isNotAfterDot && isNotTypeAlias diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs index 67263a593a..0faf11e554 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineTypeHintTests.fs @@ -197,7 +197,7 @@ let x Assert.IsEmpty(result) [] - let ``Hints are not shown for unsolved types in for expressions`` () = + let ``Hints are not shown for unsolved types in _for_ expressions in collections`` () = let code = """ let _ = [ for x ] @@ -208,6 +208,22 @@ let _ = [ for x ] Assert.IsEmpty(result) + [] + let ``Hints are not shown for unsolved types in _for_ expressions within computational expressions`` () = + let code = + """ +do task { + for x + + do! Task.Delay 0 + } +""" + let document = getFsDocument code + + let result = getTypeHints document + + Assert.IsEmpty(result) + [] let ``Hints are shown for IWSAM`` () = let code =