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
17 changes: 6 additions & 11 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3320,7 +3320,7 @@ module EstablishTypeDefinitionCores =

let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envinner
let envinner = MakeInnerEnvForTyconRef envinner thisTyconRef false

let multiCaseUnionStructCheck (unionCases: UnionCase list) =
if tycon.IsStructRecordOrUnionTycon && unionCases.Length > 1 then
let fieldNames = [ for uc in unionCases do for ft in uc.FieldTable.TrueInstanceFieldsAsList do yield (ft.LogicalName, ft.Range) ]
Expand All @@ -3337,25 +3337,17 @@ module EstablishTypeDefinitionCores =
// Record fields should be visible from IntelliSense, so add fake names for them (similarly to "let a = ..")
for fspec in fields do
if not fspec.IsCompilerGenerated then
let info = RecdFieldInfo(thisTyInst, thisTyconRef.MakeNestedRecdFieldRef fspec)
let nenv' = AddFakeNameToNameEnv fspec.LogicalName nenv (Item.RecdField info)
// Name resolution gives better info for tooltips
let item = Item.RecdField(FreshenRecdFieldRef cenv.nameResolver m (thisTyconRef.MakeNestedRecdFieldRef fspec))
CallNameResolutionSink cenv.tcSink (fspec.Range, nenv, item, emptyTyparInst, ItemOccurence.Binding, ad)
// Environment is needed for completions
CallEnvSink cenv.tcSink (fspec.Range, nenv', ad)

// Notify the Language Service about constructors in discriminated union declaration
let writeFakeUnionCtorsToSink (unionCases: UnionCase list) =
let nenv = envinner.NameEnv
// Constructors should be visible from IntelliSense, so add fake names for them
for unionCase in unionCases do
let info = UnionCaseInfo(thisTyInst, mkUnionCaseRef thisTyconRef unionCase.Id.idText)
let nenv' = AddFakeNameToNameEnv unionCase.Id.idText nenv (Item.UnionCase(info, false))
// Report to both - as in previous function
let item = Item.UnionCase(info, false)
CallNameResolutionSink cenv.tcSink (unionCase.Range, nenv, item, emptyTyparInst, ItemOccurence.Binding, ad)
CallEnvSink cenv.tcSink (unionCase.Id.idRange, nenv', ad)

let typeRepr, baseValOpt, safeInitInfo =
match synTyconRepr with
Expand Down Expand Up @@ -3408,7 +3400,7 @@ module EstablishTypeDefinitionCores =
else
TNoRepr, None, NoSafeInitInfo

| SynTypeDefnSimpleRepr.Union (_, unionCases, _) ->
| SynTypeDefnSimpleRepr.Union (_, unionCases, mRepr) ->
noCLIMutableAttributeCheck()
noMeasureAttributeCheck()
noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedDU
Expand All @@ -3421,10 +3413,11 @@ module EstablishTypeDefinitionCores =
multiCaseUnionStructCheck unionCases

writeFakeUnionCtorsToSink unionCases
CallEnvSink cenv.tcSink (mRepr, envinner.NameEnv, ad)
let repr = Construct.MakeUnionRepr unionCases
repr, None, NoSafeInitInfo

| SynTypeDefnSimpleRepr.Record (_, fields, _) ->
| SynTypeDefnSimpleRepr.Record (_, fields, mRepr) ->
noMeasureAttributeCheck()
noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedRecord
noAbstractClassAttributeCheck()
Expand All @@ -3433,6 +3426,8 @@ module EstablishTypeDefinitionCores =
let recdFields = TcRecdUnionAndEnumDeclarations.TcNamedFieldDecls cenv envinner innerParent false tpenv fields
recdFields |> CheckDuplicates (fun f -> f.Id) "field" |> ignore
writeFakeRecordFieldsToSink recdFields
CallEnvSink cenv.tcSink (mRepr, envinner.NameEnv, ad)

let data =
{
fsobjmodel_cases = Construct.MakeUnionCases []
Expand Down
5 changes: 3 additions & 2 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,9 @@ let AddDeclaredTypars check typars env =
if isNil typars then
env
else
let env = { env with eNameResEnv = AddDeclaredTyparsToNameEnv check env.eNameResEnv typars }
{ env with eUngeneralizableItems = List.foldBack (mkTyparTy >> addFreeItemOfTy) typars env.eUngeneralizableItems }
{ env with
eUngeneralizableItems = List.foldBack (mkTyparTy >> addFreeItemOfTy) typars env.eUngeneralizableItems
eNameResEnv = AddDeclaredTyparsToNameEnv check env.eNameResEnv typars}

/// Environment of implicitly scoped type parameters, e.g. 'a in "(x: 'a)"

Expand Down
2 changes: 1 addition & 1 deletion tests/FSharp.Compiler.Service.Tests/TooltipTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ type Bar = {
}
"""

testXmlDocFallbackToSigFileWhileInImplFile sigSource implSource 5 9 " SomeField: int" [ "SomeField" ] "Some sig comment on record field"
testXmlDocFallbackToSigFileWhileInImplFile sigSource implSource 5 13 " SomeField: int" [ "SomeField" ] "Some sig comment on record field"


[<Test>]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,31 @@ type A<'lType> = { Field: l }

VerifyCompletionList(fileContents, "Field: l", [ "LanguagePrimitives"; "List" ], [ "let"; "log" ])

[<Fact>]
let ``Completion list at record declaration site contains type parameter and record`` () =
let fileContents =
"""
type ARecord<'keyType> = {
Field: key
Field2: AR
Field3: ARecord<ke
}
with
static member Create () = { F }
member x.F () = typeof<AR
member _.G = typeof<ke

let x = { F }
"""

VerifyCompletionList(fileContents, ": key", [ "keyType" ], [])
VerifyCompletionList(fileContents, ": AR", [ "ARecord" ], [])
VerifyCompletionList(fileContents, ": ARecord<ke", [ "ARecord" ], [])
VerifyCompletionList(fileContents, "typeof<AR", [ "ARecord" ], [])
VerifyCompletionList(fileContents, "typeof<ke", [ "keyType" ], [])
VerifyCompletionList(fileContents, "Create () = { F", [ "Field"; "Field2"; "Field3" ], [])
VerifyCompletionList(fileContents, "let x = { F", [ "Field"; "Field2"; "Field3" ], [])

[<Fact>]
let ``No completion on record stub with no fields at declaration site`` () =
let fileContents =
Expand Down Expand Up @@ -1198,14 +1223,29 @@ type A<'lType> =
VerifyCompletionList(fileContents, "of l", [ "LanguagePrimitives"; "List"; "lType" ], [ "let"; "log" ])

[<Fact>]
let ``Completion list on union case type at declaration site contains type parameter`` () =
let ``Completion list at union declaration site contains type parameter and union`` () =
let fileContents =
"""
type A<'keyType> =
type AUnion<'keyType> =
| Case of key
| Case2 of AU
| Case3 of AUnion<ke

with
static member Create () = Cas
member x.F () = typeof<AU
member _.G = typeof<ke

let x = c
"""

VerifyCompletionList(fileContents, "of key", [ "keyType" ], [])
VerifyCompletionList(fileContents, "of AU", [ "AUnion" ], [])
VerifyCompletionList(fileContents, "of AUnion<ke", [ "keyType" ], [])
VerifyCompletionList(fileContents, "typeof<AU", [ "AUnion" ], [])
VerifyCompletionList(fileContents, "typeof<ke", [ "keyType" ], [])
VerifyCompletionList(fileContents, "= Cas", [ "Case"; "Case2"; "Case3" ], [])
VerifyCompletionList(fileContents, "let x = c", [ "Case"; "Case2"; "Case3" ], [])

[<Fact>]
let ``Completion list on a union identifier and a dot in a match clause contains union cases`` () =
Expand Down