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
10 changes: 9 additions & 1 deletion src/fsharp/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4364,7 +4364,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
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not really sure ResolvePartialLongIdentPrim is the place to insert these type variables as it's outside of the FCS.

Copy link
Member

Choose a reason for hiding this comment

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

Not sure exactly what you mean by 'outside of FCS' here. This seems like a reasonable change, and sometimes lower level changes need to be made in order to surface better behaviors in the user-facing APIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, it's outside of the service folder, so I thought this file was part of the compiler proper.


| id :: rest ->

Expand Down
15 changes: 9 additions & 6 deletions src/fsharp/NicePrint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -2426,6 +2427,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
Expand Down
2 changes: 2 additions & 0 deletions src/fsharp/NicePrint.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 9 additions & 8 deletions src/fsharp/service/FSharpCheckerResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,14 +1041,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 ->
Expand Down
3 changes: 2 additions & 1 deletion src/fsharp/service/ServiceConstants.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ type FSharpGlyph =
| Union
| Variable
| ExtensionMethod
| Error
| Error
| TypeParameter
16 changes: 12 additions & 4 deletions src/fsharp/service/ServiceDeclarationLists.fs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,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()
Expand Down Expand Up @@ -846,7 +851,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
Expand Down Expand Up @@ -1027,9 +1032,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)
Expand Down
3 changes: 3 additions & 0 deletions src/fsharp/service/ServiceParsedInputOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,9 @@ module ParsedInput =
| _ ->
defaultTraverse expr

// Unchecked.defaultof<str$>
| SynExpr.TypeApp (typeArgsRange = range) when rangeContainsPos range pos ->
Some CompletionContext.PatternType
| _ -> defaultTraverse expr

member _.VisitRecordField(path, copyOpt, field) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2652,6 +2652,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)
Expand All @@ -2676,6 +2677,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()
Expand All @@ -2697,6 +2699,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
Expand All @@ -2718,6 +2721,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()
Expand All @@ -2739,6 +2743,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
Expand Down
1 change: 1 addition & 0 deletions vsintegration/src/FSharp.Editor/Common/Extensions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ type NavigationItem with
| Some SynAccess.Internal -> FSharpRoslynGlyph.ExtensionMethodInternal
| _ -> FSharpRoslynGlyph.ExtensionMethodPublic
| FSharpGlyph.Error -> FSharpRoslynGlyph.Error
| FSharpGlyph.TypeParameter -> FSharpRoslynGlyph.TypeParameter

[<RequireQualifiedAccess>]
module String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -345,6 +347,7 @@ module internal Tokenizer =
| Internal -> Glyph.ClassInternal
| Protected -> Glyph.ClassProtected
| Private -> Glyph.ClassPrivate
| :? FSharpGenericParameter -> Glyph.TypeParameter
| _ -> Glyph.None


Expand Down
1 change: 1 addition & 0 deletions vsintegration/src/FSharp.LanguageService/Intellisense.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
56 changes: 48 additions & 8 deletions vsintegration/tests/UnitTests/CompletionProviderTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -751,9 +751,9 @@ type A = { le: string }
VerifyNoCompletionList(fileContents, "le")

[<Test>]
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"])

Expand All @@ -774,20 +774,28 @@ type A =
VerifyNoCompletionList(fileContents, "str")

[<Test>]
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"])

[<Test>]
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"])

[<Test>]
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"], [])

[<Test>]
let ``Completion list on type alias contains modules and types but not keywords or functions``() =
Expand All @@ -804,6 +812,38 @@ type A =
"""
VerifyNoCompletionList(fileContents, "| C")

[<Test>]
let ``Completion list in generic function body contains type parameter``() =
let fileContents = """
let Null<'wrappedType> () =
Unchecked.defaultof<wrapp>
"""
VerifyCompletionList(fileContents, "defaultof<wrapp", ["wrappedType"], [])

[<Test>]
let ``Completion list in generic method body contains type parameter``() =
let fileContents = """
type A () =
member _.Null<'wrappedType> () = Unchecked.defaultof<wrapp>
"""
VerifyCompletionList(fileContents, "defaultof<wrapp", ["wrappedType"], [])

[<Test>]
let ``Completion list in generic class method body contains type parameter``() =
let fileContents = """
type A<'wrappedType> () =
member _.Null () = Unchecked.defaultof<wrapp>
"""
VerifyCompletionList(fileContents, "defaultof<wrapp", ["wrappedType"], [])

[<Test>]
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