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
60 changes: 46 additions & 14 deletions src/fsharp/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/fsharp/typecheck/sigs/neg01.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion tests/fsharp/typecheck/sigs/neg14.bsl
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions tests/fsharp/typecheck/sigs/neg15.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion tests/fsharp/typecheck/sigs/neg17.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
10 changes: 10 additions & 0 deletions tests/fsharpqa/Source/Warnings/SuggestRecordLabels.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// #Warnings
//<Expects status="Error" id="FS0039">The field, constructor or member 'ello' is not defined. Maybe you want one of the following: Hello</Expects>

type MyRecord = { Hello: int; World: bool}

let r = { Hello = 2 ; World = true}

let x = r.ello

exit 0
11 changes: 11 additions & 0 deletions tests/fsharpqa/Source/Warnings/SuggestUnionCases.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// #Warnings
//<Expects status="Error" id="FS0039">The field, constructor or member 'AntherCase' is not defined. Maybe you want one of the following: AnotherCase</Expects>

type MyUnion =
| ASimpleCase
| AnotherCase of int

let u = MyUnion.AntherCase


exit 0
2 changes: 2 additions & 0 deletions tests/fsharpqa/Source/Warnings/env.lst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down