diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs
index d085460b95e..50587d55eab 100644
--- a/src/fsharp/NameResolution.fs
+++ b/src/fsharp/NameResolution.fs
@@ -1909,6 +1909,19 @@ let DecodeFSharpEvent (pinfos:PropInfo list) ad g (ncenv:NameResolver) m =
| _ ->
None
+/// Returns all record label names for the given type.
+let GetRecordLabelsForType g nenv typ =
+ if isRecdTy g typ then
+ let typeName = NicePrint.minimalStringOfType nenv.eDisplayEnv typ
+ nenv.eFieldLabels
+ |> Seq.filter (fun kv ->
+ kv.Value
+ |> List.map (fun r -> r.TyconRef.DisplayName)
+ |> List.exists ((=) typeName))
+ |> Seq.map (fun kv -> kv.Key)
+ |> Set.ofSeq
+ else
+ Set.empty
// REVIEW: this shows up on performance logs. Consider for example endless resolutions of "List.map" to
// the empty set of results, or "x.Length" for a list or array type. This indicates it could be worth adding a cache here.
@@ -2011,12 +2024,25 @@ let rec ResolveLongIdentInTypePrim (ncenv:NameResolver) nenv lookupKind (resInfo
|> List.filter (fun m -> not m.IsClassConstructor && not m.IsConstructor)
|> List.map (fun m -> m.DisplayName)
|> Set.ofList
-
-
+ let suggestions5 = GetRecordLabelsForType g nenv typ
+ let suggestions6 =
+ match lookupKind with
+ | LookupKind.Expr | LookupKind.Pattern ->
+ if isAppTy g typ then
+ let tcref,_ = destAppTy g typ
+ tcref.UnionCasesArray
+ |> Array.map (fun uc -> uc.DisplayName)
+ |> Set.ofArray
+ else
+ Set.empty
+ | _ -> Set.empty
+
suggestions1
|> Set.union suggestions2
|> Set.union suggestions3
|> Set.union suggestions4
+ |> Set.union suggestions5
+ |> Set.union suggestions6
raze (UndefinedName (depth,FSComp.SR.undefinedNameFieldConstructorOrMember, id, suggestMembers))
@@ -2140,8 +2166,21 @@ let rec ResolveExprLongIdentInModuleOrNamespace (ncenv:NameResolver) nenv (typeN
|> Seq.filter (fun kv -> IsEntityAccessible ncenv.amap m ad (modref.NestedTyconRef kv.Value))
|> Seq.map (fun e -> e.Value.DisplayName)
|> Set.ofSeq
+
+ let unions =
+ modref.ModuleOrNamespaceType.AllEntities
+ |> Seq.collect (fun tycon ->
+ let hasRequireQualifiedAccessAttribute = HasFSharpAttribute ncenv.g ncenv.g.attrib_RequireQualifiedAccessAttribute tycon.Attribs
+ if hasRequireQualifiedAccessAttribute then
+ [||]
+ else
+ tycon.UnionCasesArray)
+ |> Seq.map (fun uc -> uc.DisplayName)
+ |> Set.ofSeq
- Set.union types submodules // TODO: Add unions
+ types
+ |> Set.union submodules
+ |> Set.union unions
| _ -> Set.empty
raze (UndefinedName(depth,FSComp.SR.undefinedNameValueConstructorNamespaceOrType,id,suggestPossibleTypes))
@@ -2757,15 +2796,8 @@ let rec ResolveFieldInModuleOrNamespace (ncenv:NameResolver) nenv ad (resInfo:Re
error(InternalError("ResolveFieldInModuleOrNamespace",m))
/// Suggest other labels of the same record
-let SuggestOtherLabelsOfSameRecordType (nenv:NameResolutionEnv) typeName (id:Ident) (allFields:Ident list) =
- let labelsOfPossibleRecord =
- nenv.eFieldLabels
- |> Seq.filter (fun kv ->
- kv.Value
- |> List.map (fun r -> r.TyconRef.DisplayName)
- |> List.exists ((=) typeName))
- |> Seq.map (fun kv -> kv.Key)
- |> Set.ofSeq
+let SuggestOtherLabelsOfSameRecordType g (nenv:NameResolutionEnv) typ (id:Ident) (allFields:Ident list) =
+ let labelsOfPossibleRecord = GetRecordLabelsForType g nenv typ
let givenFields =
allFields
@@ -2830,10 +2862,10 @@ let ResolveFieldPrim (ncenv:NameResolver) nenv ad typ (mp,id:Ident) allFields =
match ncenv.InfoReader.TryFindRecdOrClassFieldInfoOfType(id.idText,m,typ) with
| Some (RecdFieldInfo(_,rfref)) -> [ResolutionInfo.Empty, FieldResolution(rfref,false)]
| None ->
- let typeName = NicePrint.minimalStringOfType nenv.eDisplayEnv typ
if isRecdTy g typ then
// record label doesn't belong to record type -> suggest other labels of same record
- let suggestLabels() = SuggestOtherLabelsOfSameRecordType nenv typeName id allFields
+ let suggestLabels() = SuggestOtherLabelsOfSameRecordType g nenv typ id allFields
+ let typeName = NicePrint.minimalStringOfType nenv.eDisplayEnv typ
let errorText = FSComp.SR.nrRecordDoesNotContainSuchLabel(typeName,id.idText)
error(ErrorWithSuggestions(errorText, m, id.idText, suggestLabels))
else
diff --git a/tests/fsharp/typecheck/sigs/neg01.bsl b/tests/fsharp/typecheck/sigs/neg01.bsl
index a0c3aec5bb4..069e0862725 100644
--- a/tests/fsharp/typecheck/sigs/neg01.bsl
+++ b/tests/fsharp/typecheck/sigs/neg01.bsl
@@ -3,4 +3,4 @@ neg01a.fsi(24,8,25,7): typecheck error FS0913: Types cannot contain nested type
neg01a.fs(22,8,23,7): typecheck error FS0913: Types cannot contain nested type definitions
-neg01b.fs(2,13,2,14): typecheck error FS0039: The value, constructor, namespace or type 'X' is not defined. Maybe you want one of the following: fieldsInWrongOrder, missingConstructorInSignature, missingFieldInSignature, missingInterfaceInImplementation, missingInterfaceInSignature
+neg01b.fs(2,13,2,14): typecheck error FS0039: The value, constructor, namespace or type 'X' is not defined. Maybe you want one of the following: A, B, fieldsInWrongOrder, missingConstructorInSignature, missingFieldInSignature
diff --git a/tests/fsharp/typecheck/sigs/neg14.bsl b/tests/fsharp/typecheck/sigs/neg14.bsl
index d677a803339..224682fff16 100644
--- a/tests/fsharp/typecheck/sigs/neg14.bsl
+++ b/tests/fsharp/typecheck/sigs/neg14.bsl
@@ -1,4 +1,4 @@
neg14a.fs(9,6,9,33): typecheck error FS0343: The type 'missingInterfaceInSignature' implements 'System.IComparable' explicitly but provides no corresponding override for 'Object.Equals'. An implementation of 'Object.Equals' has been automatically provided, implemented via 'System.IComparable'. Consider implementing the override 'Object.Equals' explicitly
-neg14b.fs(2,13,2,14): typecheck error FS0039: The value, constructor, namespace or type 'X' is not defined. Maybe you want one of the following: fieldsInWrongOrder, missingConstructorInSignature, missingFieldInSignature, missingInterfaceInImplementation, missingInterfaceInSignature
+neg14b.fs(2,13,2,14): typecheck error FS0039: The value, constructor, namespace or type 'X' is not defined. Maybe you want one of the following: A, B, fieldsInWrongOrder, missingConstructorInSignature, missingFieldInSignature
diff --git a/tests/fsharp/typecheck/sigs/neg15.bsl b/tests/fsharp/typecheck/sigs/neg15.bsl
index 0726e5b5314..d7419af9bb5 100644
--- a/tests/fsharp/typecheck/sigs/neg15.bsl
+++ b/tests/fsharp/typecheck/sigs/neg15.bsl
@@ -29,11 +29,11 @@ neg15.fs(115,19,115,48): typecheck error FS0072: Lookup on object of indetermina
neg15.fs(116,20,116,73): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
-neg15.fs(122,32,122,57): typecheck error FS0039: The value, constructor, namespace or type 'InternalTagOfInternalType' is not defined. Maybe you want one of the following: InternalUnionType, InternalRecordType, UnionTypeWithPrivateRepresentation
+neg15.fs(122,32,122,57): typecheck error FS0039: The value, constructor, namespace or type 'InternalTagOfInternalType' is not defined. Maybe you want one of the following: InternalUnionType, InternalRecordType, DefaultTagOfInternalType, DefaultTagOfPrivateType, UnionTypeWithPrivateRepresentation
neg15.fs(128,31,128,61): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
-neg15.fs(135,31,135,56): typecheck error FS0039: The value, constructor, namespace or type 'InternalTagOfInternalType' is not defined. Maybe you want one of the following: InternalUnionType, InternalRecordType, UnionTypeWithPrivateRepresentation
+neg15.fs(135,31,135,56): typecheck error FS0039: The value, constructor, namespace or type 'InternalTagOfInternalType' is not defined. Maybe you want one of the following: InternalUnionType, InternalRecordType, DefaultTagOfInternalType, DefaultTagOfPrivateType, UnionTypeWithPrivateRepresentation
neg15.fs(141,30,141,60): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
diff --git a/tests/fsharp/typecheck/sigs/neg17.bsl b/tests/fsharp/typecheck/sigs/neg17.bsl
index dd78a8273b6..cddb2c38d61 100644
--- a/tests/fsharp/typecheck/sigs/neg17.bsl
+++ b/tests/fsharp/typecheck/sigs/neg17.bsl
@@ -21,7 +21,7 @@ neg17b.fs(16,19,16,48): typecheck error FS0072: Lookup on object of indeterminat
neg17b.fs(17,19,17,47): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
-neg17b.fs(21,31,21,77): typecheck error FS0039: The value, constructor, namespace or type 'DefaultTagOfUnionTypeWithPrivateRepresentation' is not defined. Maybe you want one of the following: UnionTypeWithPrivateRepresentation, RecordTypeWithPrivateRepresentation
+neg17b.fs(21,31,21,77): typecheck error FS0039: The value, constructor, namespace or type 'DefaultTagOfUnionTypeWithPrivateRepresentation' is not defined. Maybe you want one of the following: DefaultTagOfInternalType, DefaultTagOfPrivateType, UnionTypeWithPrivateRepresentation, RecordTypeWithPrivateRepresentation
neg17b.fs(29,31,29,61): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
diff --git a/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs b/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs
new file mode 100644
index 00000000000..5bb65ee9da5
--- /dev/null
+++ b/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs
@@ -0,0 +1,10 @@
+// #Warnings
+//The field, constructor or member 'ello' is not defined. Maybe you want one of the following: Hello
+
+type MyRecord = { Hello: int; World: bool}
+
+let r = { Hello = 2 ; World = true}
+
+let x = r.ello
+
+exit 0
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Warnings/SuggestUnionCases.fs b/tests/fsharpqa/Source/Warnings/SuggestUnionCases.fs
new file mode 100644
index 00000000000..edc0c3819fb
--- /dev/null
+++ b/tests/fsharpqa/Source/Warnings/SuggestUnionCases.fs
@@ -0,0 +1,11 @@
+// #Warnings
+//The field, constructor or member 'AntherCase' is not defined. Maybe you want one of the following: AnotherCase
+
+type MyUnion =
+| ASimpleCase
+| AnotherCase of int
+
+let u = MyUnion.AntherCase
+
+
+exit 0
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Warnings/env.lst b/tests/fsharpqa/Source/Warnings/env.lst
index 55bbfc61675..5a35a41373a 100644
--- a/tests/fsharpqa/Source/Warnings/env.lst
+++ b/tests/fsharpqa/Source/Warnings/env.lst
@@ -28,6 +28,8 @@
SOURCE=SuggestModules.fs # SuggestModules.fs
SOURCE=SuggestMethods.fs # SuggestMethods.fs
SOURCE=SuggestAttributes.fs # SuggestAttributes.fs
+ SOURCE=SuggestRecordLabels.fs SCFLAGS="--vserrors" # SuggestRecordLabels.fs
+ SOURCE=SuggestUnionCases.fs SCFLAGS="--vserrors" # SuggestUnionCases.fs
SOURCE=SuggestTypesInNamespace.fs # SuggestTypesInNamespace.fs
SOURCE=DontSuggestCompletelyWrongStuff.fs SCFLAGS="--vserrors" # DontSuggestCompletelyWrongStuff.fs
SOURCE=SuggestTypesInNamespaceVS.fs SCFLAGS="--vserrors" # SuggestTypesInNamespaceVS.fs