From a77a71ee32224d134e40b0693a713057a27ab9f7 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Wed, 28 Dec 2016 09:46:27 +0100 Subject: [PATCH 1/8] Show that we can't suggest record labels --- tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs | 7 +++++++ tests/fsharpqa/Source/Warnings/env.lst | 1 + 2 files changed, 8 insertions(+) create mode 100644 tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs diff --git a/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs b/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs new file mode 100644 index 00000000000..578b659951c --- /dev/null +++ b/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs @@ -0,0 +1,7 @@ +// #Warnings +//The value, constructor, namespace or type 'DateTie' is not defined +//Maybe you want one of the following: DateTime, DateTimeKind, DateTimeOffset + +let x = System.DateTie.MaxValue + +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..763070559ad 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -28,6 +28,7 @@ SOURCE=SuggestModules.fs # SuggestModules.fs SOURCE=SuggestMethods.fs # SuggestMethods.fs SOURCE=SuggestAttributes.fs # SuggestAttributes.fs + SOURCE=SuggestRecordLabels.fs # SuggestRecordLabels.fs SOURCE=SuggestTypesInNamespace.fs # SuggestTypesInNamespace.fs SOURCE=DontSuggestCompletelyWrongStuff.fs SCFLAGS="--vserrors" # DontSuggestCompletelyWrongStuff.fs SOURCE=SuggestTypesInNamespaceVS.fs SCFLAGS="--vserrors" # SuggestTypesInNamespaceVS.fs From 8a9eed7afe8cee358cad8ec6e992999cabe6126e Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Wed, 28 Dec 2016 09:47:43 +0100 Subject: [PATCH 2/8] Suggest record labels - fixes #2117 --- src/fsharp/NameResolution.fs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs index d085460b95e..87ea92ed81d 100644 --- a/src/fsharp/NameResolution.fs +++ b/src/fsharp/NameResolution.fs @@ -2011,12 +2011,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 = + 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 suggestions1 |> Set.union suggestions2 |> Set.union suggestions3 |> Set.union suggestions4 + |> Set.union suggestions5 raze (UndefinedName (depth,FSComp.SR.undefinedNameFieldConstructorOrMember, id, suggestMembers)) From ff40a6103c19c620a1bdf0707a870061574f80e1 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Wed, 28 Dec 2016 11:15:25 +0100 Subject: [PATCH 3/8] cleanup --- src/fsharp/NameResolution.fs | 42 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs index 87ea92ed81d..3d8df04605e 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,19 +2024,7 @@ 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 = - 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 - + let suggestions5 = GetRecordLabelsForType g nenv typ suggestions1 |> Set.union suggestions2 @@ -2770,15 +2771,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 @@ -2843,10 +2837,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 From d11eeb502d472593651522ba24bad878e3b518f9 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Wed, 28 Dec 2016 11:19:31 +0100 Subject: [PATCH 4/8] Fix the test --- tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs | 9 ++++++--- tests/fsharpqa/Source/Warnings/env.lst | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs b/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs index 578b659951c..5bb65ee9da5 100644 --- a/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs +++ b/tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs @@ -1,7 +1,10 @@ // #Warnings -//The value, constructor, namespace or type 'DateTie' is not defined -//Maybe you want one of the following: DateTime, DateTimeKind, DateTimeOffset +//The field, constructor or member 'ello' is not defined. Maybe you want one of the following: Hello -let x = System.DateTie.MaxValue +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/env.lst b/tests/fsharpqa/Source/Warnings/env.lst index 763070559ad..d3453cc1a2a 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -28,7 +28,7 @@ SOURCE=SuggestModules.fs # SuggestModules.fs SOURCE=SuggestMethods.fs # SuggestMethods.fs SOURCE=SuggestAttributes.fs # SuggestAttributes.fs - SOURCE=SuggestRecordLabels.fs # SuggestRecordLabels.fs + SOURCE=SuggestRecordLabels.fs SCFLAGS="--vserrors" # SuggestRecordLabels.fs SOURCE=SuggestTypesInNamespace.fs # SuggestTypesInNamespace.fs SOURCE=DontSuggestCompletelyWrongStuff.fs SCFLAGS="--vserrors" # DontSuggestCompletelyWrongStuff.fs SOURCE=SuggestTypesInNamespaceVS.fs SCFLAGS="--vserrors" # SuggestTypesInNamespaceVS.fs From 286e3946fc46804b90a8db993a37b09af1a6338e Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Wed, 28 Dec 2016 11:35:56 +0100 Subject: [PATCH 5/8] New test for union cases --- tests/fsharpqa/Source/Warnings/SuggestUnionCases.fs | 11 +++++++++++ tests/fsharpqa/Source/Warnings/env.lst | 1 + 2 files changed, 12 insertions(+) create mode 100644 tests/fsharpqa/Source/Warnings/SuggestUnionCases.fs 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 d3453cc1a2a..5a35a41373a 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -29,6 +29,7 @@ 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 From 15766b51d68870d45143957fe4804981ee99e286 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Wed, 28 Dec 2016 11:47:16 +0100 Subject: [PATCH 6/8] Suggest union cases --- src/fsharp/NameResolution.fs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs index 3d8df04605e..6ee823b880a 100644 --- a/src/fsharp/NameResolution.fs +++ b/src/fsharp/NameResolution.fs @@ -2025,12 +2025,24 @@ let rec ResolveLongIdentInTypePrim (ncenv:NameResolver) nenv lookupKind (resInfo |> 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)) From d1dc5355259d08332a484a38c02cac5c36e0cee2 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Wed, 28 Dec 2016 15:37:51 +0100 Subject: [PATCH 7/8] Suggest more unions --- src/fsharp/NameResolution.fs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs index 6ee823b880a..50587d55eab 100644 --- a/src/fsharp/NameResolution.fs +++ b/src/fsharp/NameResolution.fs @@ -2166,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)) From 8a15b4e0cf0704f48fd0dd69f9f18da22be190d1 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Wed, 28 Dec 2016 18:26:29 +0100 Subject: [PATCH 8/8] Fix tests --- tests/fsharp/typecheck/sigs/neg01.bsl | 2 +- tests/fsharp/typecheck/sigs/neg14.bsl | 2 +- tests/fsharp/typecheck/sigs/neg15.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg17.bsl | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) 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.