Skip to content

Commit 8b219f2

Browse files
committed
Add a compiler warning for lower case literals in patterns
Add unit tests
1 parent a4c0c9c commit 8b219f2

File tree

7 files changed

+49
-4
lines changed

7 files changed

+49
-4
lines changed

src/fsharp/FSComp.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,3 +1344,4 @@ estApplyStaticArgumentsForMethodNotImplemented,"A type provider implemented GetS
13441344
3187,checkNotSufficientlyGenericBecauseOfScope,"Type inference caused the type variable %s to escape its scope. Consider adding an explicit type parameter declaration or adjusting your code to be less generic."
13451345
3188,checkNotSufficientlyGenericBecauseOfScopeAnon,"Type inference caused an inference type variable to escape its scope. Consider adding type annotations to make your code less generic."
13461346
3189,checkRaiseFamilyFunctionArgumentCount,"Redundant arguments are being ignored in function '%s'. Expected %d but got %d arguments."
1347+
3190,checkLowercaseLiteralBindingInPattern,"Lowercase literal '%s' is being shadowed by a new pattern with the same name. Only uppercase and module-prefixed literals can be used as named patterns."

src/fsharp/NameResolution.fs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,10 @@ let private AddPartsOfTyconRefToNameEnv bulkAddMode ownDefinition (g:TcGlobals)
606606
ePatItems = ePatItems
607607
eIndexedExtensionMembers = eIndexedExtensionMembers
608608
eUnindexedExtensionMembers = eUnindexedExtensionMembers }
609-
609+
610+
let TryFindPatternByName name {ePatItems = patternMap} =
611+
NameMap.tryFind name patternMap
612+
610613
/// Add a set of type definitions to the name resolution environment
611614
let AddTyconRefsToNameEnv bulkAddMode ownDefinition g amap m root nenv tcrefs =
612615
let env = List.fold (AddPartsOfTyconRefToNameEnv bulkAddMode ownDefinition g amap m) nenv tcrefs

src/fsharp/NameResolution.fsi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ type FullyQualifiedFlag =
101101
[<RequireQualifiedAccess>]
102102
type BulkAdd = Yes | No
103103

104+
/// Lookup patterns in name resolution environment
105+
val internal TryFindPatternByName : string -> NameResolutionEnv -> Item option
106+
104107
/// Add extra items to the environment for Visual Studio, e.g. static members
105108
val internal AddFakeNamedValRefToNameEnv : string -> NameResolutionEnv -> ValRef -> NameResolutionEnv
106109

src/fsharp/TypeChecker.fs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4691,7 +4691,7 @@ and TcSimplePatsOfUnknownType cenv optArgsOK checkCxs env tpenv spats =
46914691
let argty = NewInferenceType ()
46924692
TcSimplePats cenv optArgsOK checkCxs argty env (tpenv,NameMap.empty,Set.empty) spats
46934693

4694-
and TcPatBindingName _cenv _env id ty isMemberThis vis1 topValData (inlineFlag,declaredTypars,argAttribs,isMutable,vis2,compgen) (names,takenNames:Set<string>) =
4694+
and TcPatBindingName _cenv env id ty isMemberThis vis1 topValData (inlineFlag,declaredTypars,argAttribs,isMutable,vis2,compgen) (names,takenNames:Set<string>) =
46954695
let vis = if isSome vis1 then vis1 else vis2
46964696
if takenNames.Contains id.idText then errorR (VarBoundTwice id)
46974697
let baseOrThis = if isMemberThis then MemberThisVal else NormalVal
@@ -4700,7 +4700,14 @@ and TcPatBindingName _cenv _env id ty isMemberThis vis1 topValData (inlineFlag,d
47004700
(fun (TcPatPhase2Input values) ->
47014701
let (vspec,typeScheme) =
47024702
match values.TryFind id.idText with
4703-
| Some x -> x
4703+
| Some value ->
4704+
let name = id.idText
4705+
if not (String.IsNullOrEmpty name) && Char.IsLower(name.[0]) then
4706+
match TryFindPatternByName name env.eNameResEnv with
4707+
| Some (Item.Value vref) when vref.LiteralValue.IsSome ->
4708+
warning(Error(FSComp.SR.checkLowercaseLiteralBindingInPattern(id.idText),id.idRange))
4709+
| Some _ | None -> ()
4710+
value
47044711
| None -> error(Error(FSComp.SR.tcNameNotBoundInPattern(id.idText),id.idRange))
47054712
PBind(vspec,typeScheme)),
47064713
names,takenNames
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// #Regression #Diagnostics
2+
//<Expects status="warning" span="(10,5-10,14)" id="FS3190">Lowercase literal 'lowerCase' is being shadowed by a new pattern with the same name\. Only uppercase and module-prefixed literals can be used as named patterns\.$</Expects>
3+
module M
4+
5+
let [<Literal>] lowerCase = "lowerCase"
6+
let [<Literal>] UpperCase = "UpperCase"
7+
8+
let f = function
9+
| UpperCase -> "UpperCase"
10+
| lowerCase -> "LowerCase"
11+
12+
f "A" |> ignore
13+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// #Regression #Diagnostics
2+
//<Expects status="warning" span="(13,7-13,8)" id="FS0026">This rule will never be matched$</Expects>
3+
module M0
4+
5+
module m1 =
6+
let [<Literal>] lowerCase = "lowerCase"
7+
let [<Literal>] UpperCase = "UpperCase"
8+
9+
module M2 =
10+
let f = function
11+
| m1.lowerCase -> "LowerCase"
12+
| lowerCase2 -> "LowerCase2"
13+
| _ -> "Don't know"
14+
15+
printfn "%A" (M2.f "B")

tests/fsharpqa/Source/Diagnostics/General/env.lst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,7 @@ ReqPP SOURCE=W_WebExtensionsNotInPowerPack01.fs SCFLAGS="--test:ErrorRanges -r:F
125125
SOURCE=W_RaiseRedundantArgs.fs SCFLAGS="--test:ErrorRanges -a" # W_RaiseRedundantArgs.fs
126126
SOURCE=W_InvalidArgRedundantArgs.fs SCFLAGS="--test:ErrorRanges -a" # W_InvalidArgRedundantArgs.fs
127127
SOURCE=W_NullArgRedundantArgs.fs SCFLAGS="--test:ErrorRanges -a" # W_NullArgRedundantArgs.fs
128-
SOURCE=W_InvalidOpRedundantArgs.fs SCFLAGS="--test:ErrorRanges -a" # W_InvalidOpRedundantArgs.fs
128+
SOURCE=W_InvalidOpRedundantArgs.fs SCFLAGS="--test:ErrorRanges -a" # W_InvalidOpRedundantArgs.fs
129+
130+
SOURCE=W_LowercaseLiteralIgnored.fs SCFLAGS="--test:ErrorRanges" # W_LowercaseLiteralIgnored.fs
131+
SOURCE=W_LowercaseLiteralNotIgnored.fs SCFLAGS="--test:ErrorRanges" # W_LowercaseLiteralNotIgnored.fs

0 commit comments

Comments
 (0)