diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs index 85f15edd5e081a3c2ff65e1446ce3eeb231249f7..2aa62bb34cd40aa5608968fe30bf18d09be3fd33 100644 --- a/src/fsharp/NameResolution.fs +++ b/src/fsharp/NameResolution.fs @@ -4404,7 +4404,15 @@ let rec ResolvePartialLongIdentPrim (ncenv: NameResolver) (nenv: NameResolutionE |> Seq.collect (InfosForTyconConstructors ncenv m ad) |> Seq.toList - unqualifiedItems @ activePatternItems @ moduleAndNamespaceItems @ tycons @ constructors + let typeVars = + if nenv.eTypars.IsEmpty then + [] + else + nenv.eTypars + |> Seq.map (fun kvp -> Item.TypeVar (kvp.Key, kvp.Value)) + |> Seq.toList + + unqualifiedItems @ activePatternItems @ moduleAndNamespaceItems @ tycons @ constructors @ typeVars | id :: rest -> diff --git a/src/fsharp/NicePrint.fs b/src/fsharp/NicePrint.fs index 8097f7d2d58397cbd90f20c6c37fc2fe2f91c9c9..9cf39e816116f60d0b699f2e4f51fa0de690b575 100755 --- a/src/fsharp/NicePrint.fs +++ b/src/fsharp/NicePrint.fs @@ -650,12 +650,13 @@ module PrintTypes = | _, _ -> squareAngleL (sepListL (rightL (tagPunctuation ";")) ((match kind with TyparKind.Type -> [] | TyparKind.Measure -> [wordL (tagText "Measure")]) @ List.map (layoutAttrib denv) attrs)) ^^ restL and layoutTyparRef denv (typar: Typar) = - wordL - (tagTypeParameter - (sprintf "%s%s%s" - (if denv.showConstraintTyparAnnotations then prefixOfStaticReq typar.StaticReq else "'") - (if denv.showImperativeTyparAnnotations then prefixOfRigidTypar typar else "") - typar.DisplayName)) + tagTypeParameter + (sprintf "%s%s%s" + (if denv.showConstraintTyparAnnotations then prefixOfStaticReq typar.StaticReq else "'") + (if denv.showImperativeTyparAnnotations then prefixOfRigidTypar typar else "") + typar.DisplayName) + |> mkNav typar.Range + |> wordL /// Layout a single type parameter declaration, taking TypeSimplificationInfo into account /// There are several printing-cases for a typar: @@ -2437,6 +2438,8 @@ let prettyLayoutOfType denv x = x |> PrintTypes.prettyLayoutOfType denv let prettyLayoutOfTypeNoCx denv x = x |> PrintTypes.prettyLayoutOfTypeNoConstraints denv +let prettyLayoutOfTypar denv x = x |> PrintTypes.layoutTyparRef denv + let prettyStringOfTy denv x = x |> PrintTypes.prettyLayoutOfType denv |> showL let prettyStringOfTyNoCx denv x = x |> PrintTypes.prettyLayoutOfTypeNoConstraints denv |> showL diff --git a/src/fsharp/NicePrint.fsi b/src/fsharp/NicePrint.fsi index 78a2e39f74d644ee26b41449e571b51c10c6f7a0..cf497fb8b888dc5c2c1a0a78248647d53b2caa71 100644 --- a/src/fsharp/NicePrint.fsi +++ b/src/fsharp/NicePrint.fsi @@ -87,6 +87,8 @@ val prettyLayoutOfType: denv:DisplayEnv -> x:TType -> Layout val prettyLayoutOfTypeNoCx: denv:DisplayEnv -> x:TType -> Layout +val prettyLayoutOfTypar: denv:DisplayEnv -> x:Typar -> Layout + val prettyStringOfTy: denv:DisplayEnv -> x:TType -> string val prettyStringOfTyNoCx: denv:DisplayEnv -> x:TType -> string diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index e955dbdc6cda3e701e44a9e3a1e0285d9602ed89..0352d38fdd6578a3048023de20988b7b92a60c40 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -1046,14 +1046,15 @@ type internal TypeCheckInfo | Some(CompletionContext.RecordField(RecordContext.Declaration false)) -> GetDeclaredItems (parseResultsOpt, lineStr, origLongIdentOpt, colAtEndOfNamesAndResidue, residueOpt, lastDotPos, line, loc, filterCtors, resolveOverloads, false, getAllSymbols) |> Option.map (fun (items, denv, m) -> - items - |> List.filter (fun cItem -> - match cItem.Item with - | Item.ModuleOrNamespaces _ - | Item.Types _ - | Item.UnqualifiedType _ - | Item.ExnCase _ -> true - | _ -> false), denv, m) + items + |> List.filter (fun cItem -> + match cItem.Item with + | Item.ModuleOrNamespaces _ + | Item.Types _ + | Item.TypeVar _ + | Item.UnqualifiedType _ + | Item.ExnCase _ -> true + | _ -> false), denv, m) // Other completions | cc -> diff --git a/src/fsharp/service/ServiceConstants.fs b/src/fsharp/service/ServiceConstants.fs index b93d0abdab654af3c429aaf7de8e55f10f9535c6..97b6a16d228eb40ca9012aa22fec93da32f016fd 100644 --- a/src/fsharp/service/ServiceConstants.fs +++ b/src/fsharp/service/ServiceConstants.fs @@ -24,4 +24,5 @@ type FSharpGlyph = | Union | Variable | ExtensionMethod - | Error \ No newline at end of file + | Error + | TypeParameter \ No newline at end of file diff --git a/src/fsharp/service/ServiceDeclarationLists.fs b/src/fsharp/service/ServiceDeclarationLists.fs index 7c79f13b4223cd0f5cb783c3fd66c7f59a26c6fb..85cc89a1c4fa716cd332efc43b384e1a7880e84b 100644 --- a/src/fsharp/service/ServiceDeclarationLists.fs +++ b/src/fsharp/service/ServiceDeclarationLists.fs @@ -380,6 +380,11 @@ module DeclarationListHelpers = let remarks = toArray remarks ToolTipElement.Single (layout, xml, remarks=remarks) + // Type variables + | Item.TypeVar (_, typar) -> + let layout = NicePrint.prettyLayoutOfTypar denv typar + ToolTipElement.Single (toArray layout, xml) + // F# Modules and namespaces | Item.ModuleOrNamespaces(modref :: _ as modrefs) -> //let os = StringBuilder() @@ -848,7 +853,7 @@ module internal DescriptionListsImpl = | Item.CustomOperation _ -> FSharpGlyph.Method | Item.MethodGroup (_, minfos, _) when minfos |> List.forall (fun minfo -> minfo.IsExtensionMember) -> FSharpGlyph.ExtensionMethod | Item.MethodGroup _ -> FSharpGlyph.Method - | Item.TypeVar _ + | Item.TypeVar _ -> FSharpGlyph.TypeParameter | Item.Types _ -> FSharpGlyph.Class | Item.UnqualifiedType (tcref :: _) -> if tcref.IsEnumTycon || tcref.IsILEnumTycon then FSharpGlyph.Enum @@ -1031,9 +1036,12 @@ type DeclarationListInfo(declarations: DeclarationListItem[], isForType: bool, i | Some u -> u.DisplayName | None -> item.Item.DisplayNameCore let textInCode = - match item.Unresolved with - | Some u -> u.DisplayName - | None -> item.Item.DisplayName + match item.Item with + | Item.TypeVar (name, typar) -> (if typar.StaticReq = Syntax.TyparStaticReq.None then "'" else " ^") + name + | _ -> + match item.Unresolved with + | Some u -> u.DisplayName + | None -> item.Item.DisplayName textInDeclList, textInCode, items) // Filter out operators, active patterns (as values) diff --git a/src/fsharp/service/ServiceParsedInputOps.fs b/src/fsharp/service/ServiceParsedInputOps.fs index b945de135a740385e5efc9d8fd78ea31577616d8..0c4c4aaa105ba3ac9da97f6e42a59e434ca769d3 100644 --- a/src/fsharp/service/ServiceParsedInputOps.fs +++ b/src/fsharp/service/ServiceParsedInputOps.fs @@ -957,6 +957,9 @@ module ParsedInput = | _ -> defaultTraverse expr + // Unchecked.defaultof + | SynExpr.TypeApp (typeArgsRange = range) when rangeContainsPos range pos -> + Some CompletionContext.PatternType | _ -> defaultTraverse expr member _.VisitRecordField(path, copyOpt, field) = 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 51359493963210db46725f81ef96d72a34441d31..142e6a81cdc2fff6c4f5246126c3c6046d7b9e01 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -2654,6 +2654,7 @@ FSharp.Compiler.EditorServices.FSharpGlyph+Tags: Int32 Property FSharp.Compiler.EditorServices.FSharpGlyph+Tags: Int32 Struct FSharp.Compiler.EditorServices.FSharpGlyph+Tags: Int32 Type FSharp.Compiler.EditorServices.FSharpGlyph+Tags: Int32 Typedef +FSharp.Compiler.EditorServices.FSharpGlyph+Tags: Int32 TypeParameter FSharp.Compiler.EditorServices.FSharpGlyph+Tags: Int32 Union FSharp.Compiler.EditorServices.FSharpGlyph+Tags: Int32 Variable FSharp.Compiler.EditorServices.FSharpGlyph: Boolean Equals(FSharp.Compiler.EditorServices.FSharpGlyph) @@ -2678,6 +2679,7 @@ FSharp.Compiler.EditorServices.FSharpGlyph: Boolean IsProperty FSharp.Compiler.EditorServices.FSharpGlyph: Boolean IsStruct FSharp.Compiler.EditorServices.FSharpGlyph: Boolean IsType FSharp.Compiler.EditorServices.FSharpGlyph: Boolean IsTypedef +FSharp.Compiler.EditorServices.FSharpGlyph: Boolean IsTypeParameter FSharp.Compiler.EditorServices.FSharpGlyph: Boolean IsUnion FSharp.Compiler.EditorServices.FSharpGlyph: Boolean IsVariable FSharp.Compiler.EditorServices.FSharpGlyph: Boolean get_IsClass() @@ -2699,6 +2701,7 @@ FSharp.Compiler.EditorServices.FSharpGlyph: Boolean get_IsProperty() FSharp.Compiler.EditorServices.FSharpGlyph: Boolean get_IsStruct() FSharp.Compiler.EditorServices.FSharpGlyph: Boolean get_IsType() FSharp.Compiler.EditorServices.FSharpGlyph: Boolean get_IsTypedef() +FSharp.Compiler.EditorServices.FSharpGlyph: Boolean get_IsTypeParameter() FSharp.Compiler.EditorServices.FSharpGlyph: Boolean get_IsUnion() FSharp.Compiler.EditorServices.FSharpGlyph: Boolean get_IsVariable() FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph Class @@ -2720,6 +2723,7 @@ FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FShar FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph Struct FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph Type FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph Typedef +FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph TypeParameter FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph Union FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph Variable FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph get_Class() @@ -2741,6 +2745,7 @@ FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FShar FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph get_Struct() FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph get_Type() FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph get_Typedef() +FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph get_TypeParameter() FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph get_Union() FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph get_Variable() FSharp.Compiler.EditorServices.FSharpGlyph: FSharp.Compiler.EditorServices.FSharpGlyph+Tags diff --git a/vsintegration/src/FSharp.Editor/Common/Extensions.fs b/vsintegration/src/FSharp.Editor/Common/Extensions.fs index 6315654f56a4cd8b245fb687f14c624d8c54633f..60eb69bc288df04f76da954f96812b7fe69d26c3 100644 --- a/vsintegration/src/FSharp.Editor/Common/Extensions.fs +++ b/vsintegration/src/FSharp.Editor/Common/Extensions.fs @@ -221,6 +221,7 @@ type NavigationItem with | Some SynAccess.Internal -> FSharpRoslynGlyph.ExtensionMethodInternal | _ -> FSharpRoslynGlyph.ExtensionMethodPublic | FSharpGlyph.Error -> FSharpRoslynGlyph.Error + | FSharpGlyph.TypeParameter -> FSharpRoslynGlyph.TypeParameter [] module String = diff --git a/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs b/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs index 35bde0fd334c29c21c62961b8b384813658db49b..4d2159f7c3bcb70c31fdf0a580a501ceafd40855 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/Tokenizer.fs @@ -147,6 +147,7 @@ module internal Tokenizer = | Private -> Glyph.StructurePrivate | FSharpGlyph.Variable -> Glyph.Local | FSharpGlyph.Error -> Glyph.Error + | FSharpGlyph.TypeParameter -> Glyph.TypeParameter let GetImageIdForSymbol(symbolOpt:FSharpSymbol option, kind:LexerSymbolKind) = let imageId = @@ -243,6 +244,7 @@ module internal Tokenizer = | Internal -> KnownImageIds.ClassInternal | Protected -> KnownImageIds.ClassProtected | Private -> KnownImageIds.ClassPrivate + | :? FSharpGenericParameter -> KnownImageIds.Type | _ -> KnownImageIds.None if imageId = KnownImageIds.None then None @@ -345,6 +347,7 @@ module internal Tokenizer = | Internal -> Glyph.ClassInternal | Protected -> Glyph.ClassProtected | Private -> Glyph.ClassPrivate + | :? FSharpGenericParameter -> Glyph.TypeParameter | _ -> Glyph.None diff --git a/vsintegration/src/FSharp.LanguageService/Intellisense.fs b/vsintegration/src/FSharp.LanguageService/Intellisense.fs index 82e48f7a9db5e09e3ed924917e6c6050cd66cbab..c95cf70191b9c6bae1e88c587dc9bf75d780e154 100644 --- a/vsintegration/src/FSharp.LanguageService/Intellisense.fs +++ b/vsintegration/src/FSharp.LanguageService/Intellisense.fs @@ -219,6 +219,7 @@ type internal FSharpDeclarations_DEPRECATED(documentationBuilder, declarations: | FSharpGlyph.Field | FSharpGlyph.Delegate | FSharpGlyph.Variable + | FSharpGlyph.TypeParameter | FSharpGlyph.Error -> None |> Option.defaultValue ObsoleteGlyph.Class |> int diff --git a/vsintegration/tests/UnitTests/CompletionProviderTests.fs b/vsintegration/tests/UnitTests/CompletionProviderTests.fs index 9d9a60eecd1fd1b033ae9b4eb1e5e79350e982de..823fa25844414715ab36c2e8ffa3be80ddf9710a 100644 --- a/vsintegration/tests/UnitTests/CompletionProviderTests.fs +++ b/vsintegration/tests/UnitTests/CompletionProviderTests.fs @@ -751,9 +751,9 @@ type A = { le: string } VerifyNoCompletionList(fileContents, "le") [] -let ``Completion list on record field type at declaration site contains modules and types but not keywords or functions``() = +let ``Completion list on record field type at declaration site contains modules, types and type parameters but not keywords or functions``() = let fileContents = """ -type A = { Field: l } +type A<'lType> = { Field: l } """ VerifyCompletionList(fileContents, "Field: l", ["LanguagePrimitives"; "List"], ["let"; "log"]) @@ -774,20 +774,28 @@ type A = VerifyNoCompletionList(fileContents, "str") [] -let ``Completion list on union case type at declaration site contains modules and types but not keywords or functions``() = +let ``Completion list on union case type at declaration site contains modules, types and type parameters but not keywords or functions``() = let fileContents = """ -type A = +type A<'lType> = | Case of blah: int * str: l """ - VerifyCompletionList(fileContents, "str: l", ["LanguagePrimitives"; "List"], ["let"; "log"]) + VerifyCompletionList(fileContents, "str: l", ["LanguagePrimitives"; "List"; "lType"], ["let"; "log"]) [] -let ``Completion list on union case type at declaration site contains modules and types but not keywords or functions2``() = +let ``Completion list on union case type at declaration site contains modules, types and type parameters but not keywords or functions2``() = let fileContents = """ -type A = +type A<'lType> = | Case of l """ - VerifyCompletionList(fileContents, "of l", ["LanguagePrimitives"; "List"], ["let"; "log"]) + VerifyCompletionList(fileContents, "of l", ["LanguagePrimitives"; "List"; "lType"], ["let"; "log"]) + +[] +let ``Completion list on union case type at declaration site contains type parameter``() = + let fileContents = """ +type A<'keyType> = + | Case of key +""" + VerifyCompletionList(fileContents, "of key", ["keyType"], []) [] let ``Completion list on type alias contains modules and types but not keywords or functions``() = @@ -804,6 +812,38 @@ type A = """ VerifyNoCompletionList(fileContents, "| C") +[] +let ``Completion list in generic function body contains type parameter``() = + let fileContents = """ +let Null<'wrappedType> () = + Unchecked.defaultof +""" + VerifyCompletionList(fileContents, "defaultof] +let ``Completion list in generic method body contains type parameter``() = + let fileContents = """ +type A () = + member _.Null<'wrappedType> () = Unchecked.defaultof +""" + VerifyCompletionList(fileContents, "defaultof] +let ``Completion list in generic class method body contains type parameter``() = + let fileContents = """ +type A<'wrappedType> () = + member _.Null () = Unchecked.defaultof +""" + VerifyCompletionList(fileContents, "defaultof] +let ``Completion list in type application contains modules, types and type parameters but not keywords or functions``() = + let fileContents = """ +let emptyMap<'keyType, 'lValueType> () = + Map.empty<'keyType, l> +""" + VerifyCompletionList(fileContents, ", l", ["LanguagePrimitives"; "List"; "lValueType"], ["let"; "log"]) + #if EXE ShouldDisplaySystemNamespace() #endif