Skip to content
33 changes: 21 additions & 12 deletions src/Compiler/Checking/PatternMatchCompilation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,24 @@ let rec erasePartialPatterns inpPat =

and erasePartials inps =
List.map erasePartialPatterns inps

let ReportUnusedTargets (clauses: MatchClause list) dtree =
let used = HashSet<_>(accTargetsOfDecisionTree dtree [], HashIdentity.Structural)
clauses |> List.iteri (fun i c ->
let m =
match c.BoundVals, c.GuardExpr with
| [], Some guard -> guard.Range
| [ bound ], None -> bound.Id.idRange
| [ _ ], Some guard -> guard.Range
| rest, None ->
match rest with
| [ head ] -> head.Id.idRange
| _ -> c.Pattern.Range
| _, Some guard -> guard.Range

let m = withStartEnd c.Range.Start m.End m

if not (used.Contains i) then warning (RuleNeverMatched m))

let rec isPatternDisjunctive inpPat =
match inpPat with
Expand Down Expand Up @@ -1656,22 +1674,13 @@ let CompilePatternBasic
@
mkFrontiers [([], ValMap<_>.Empty)] nClauses)

let dtree =
InvestigateFrontiers
[]
frontiers

let targets = matchBuilder.CloseTargets()

let dtree = InvestigateFrontiers [] frontiers

// Report unused targets
if warnOnUnused then
let used = HashSet<_>(accTargetsOfDecisionTree dtree [], HashIdentity.Structural)

clauses |> List.iteri (fun i c ->
if not (used.Contains i) then warning (RuleNeverMatched c.Range))
ReportUnusedTargets clauses dtree

dtree, targets
dtree, matchBuilder.CloseTargets()

// Three pattern constructs can cause significant code expansion in various combinations
// - Partial active patterns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ module DynamicTypeTest =
|> typecheck
|> shouldFail
|> withDiagnostics [
(Warning 26, Line 31, Col 7, Line 31, Col 22, "This rule will never be matched")
(Warning 26, Line 32, Col 7, Line 32, Col 22, "This rule will never be matched")
(Warning 26, Line 31, Col 7, Line 31, Col 17, "This rule will never be matched")
(Warning 26, Line 32, Col 7, Line 32, Col 16, "This rule will never be matched")
]

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/DynamicTypeTest)
Expand Down Expand Up @@ -135,8 +135,8 @@ involves an indeterminate type based on information prior to this program point.
|> typecheck
|> shouldFail
|> withDiagnostics [
(Warning 26, Line 12, Col 7, Line 12, Col 22, "This rule will never be matched")
(Warning 26, Line 18, Col 7, Line 18, Col 22, "This rule will never be matched")
(Warning 26, Line 12, Col 7, Line 12, Col 16, "This rule will never be matched")
(Warning 26, Line 18, Col 7, Line 18, Col 16, "This rule will never be matched")
]

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/DynamicTypeTest)
Expand All @@ -147,4 +147,38 @@ involves an indeterminate type based on information prior to this program point.
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withSingleDiagnostic (Warning 67, Line 13, Col 7, Line 13, Col 13, "This type test or downcast will always hold")
|> withSingleDiagnostic (Warning 67, Line 13, Col 7, Line 13, Col 13, "This type test or downcast will always hold")// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/DynamicTypeTest)

[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"E_DynamicTest01.fs"|])>]
let ``DynamicTypeTest - E_DynamicTest01_fs - --test:ErrorRanges`` compilation =
compilation
|> asFs
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withDiagnostics [
(Warning 26, Line 3, Col 3, Line 3, Col 54, "This rule will never be matched")
]

[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"E_DynamicTest02.fs"|])>]
let ``DynamicTypeTest - E_DynamicTest02_fs - --test:ErrorRanges`` compilation =
compilation
|> asFs
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withDiagnostics [
(Warning 26, Line 4, Col 7, Line 4, Col 11, "This rule will never be matched")
]

[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"E_DynamicTest03.fs"|])>]
let ``DynamicTypeTest - E_DynamicTest03_fs - --test:ErrorRanges`` compilation =
compilation
|> asFs
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withDiagnostics [
(Warning 26, Line 8, Col 7, Line 8, Col 12, "This rule will never be matched")
]

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
match Unchecked.defaultof<System.ValueType> with
| :? System.Enum as (a & b) -> let c = a = b in ()
| :? System.Enum as (:? System.ConsoleKey as (d & e)) -> let f = d + e + enum 1 in ()
| g -> ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let stuff(x: obj) =
match x with
| :? option<int> -> 0x200
| null -> 0x100
| _ -> 0x500
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type A() = class end
type B1() =
inherit A()

let stuff(x: obj) =
match x with
| :? A -> 1
| :? B1 -> 2
| _ -> 3
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ but here has type
(Error 72, Line 21, Col 20, Line 21, Col 31, "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.")
(Warning 49, Line 22, Col 7, Line 22, Col 17, "Uppercase variable identifiers should not generally be used in patterns, and may indicate a missing open declaration or a misspelt pattern name.")
(Error 39, Line 23, Col 7, Line 23, Col 18, "The pattern discriminator 'Punctuation' is not defined.")
(Warning 26, Line 23, Col 7, Line 23, Col 26, "This rule will never be matched")
(Warning 26, Line 24, Col 7, Line 24, Col 40, "This rule will never be matched")
(Warning 26, Line 23, Col 7, Line 23, Col 20, "This rule will never be matched")
(Warning 26, Line 24, Col 7, Line 24, Col 8, "This rule will never be matched")
]

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/Named)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ module Simple =
|> withDiagnostics [
(Warning 25, Line 14, Col 15, Line 14, Col 16, "Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s).")
(Warning 25, Line 21, Col 31, Line 21, Col 39, "Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s).")
(Warning 26, Line 31, Col 11, Line 31, Col 18, "This rule will never be matched")
(Warning 26, Line 32, Col 11, Line 32, Col 19, "This rule will never be matched")
(Warning 26, Line 31, Col 11, Line 31, Col 12, "This rule will never be matched")
(Warning 26, Line 32, Col 11, Line 32, Col 13, "This rule will never be matched")
]

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/Simple)
Expand Down Expand Up @@ -216,7 +216,7 @@ module Simple =
|> withOptions ["--test:ErrorRanges"]
|> compile
|> shouldFail
|> withSingleDiagnostic (Warning 26, Line 10, Col 7, Line 10, Col 13, "This rule will never be matched")
|> withSingleDiagnostic (Warning 26, Line 10, Col 7, Line 10, Col 8, "This rule will never be matched")

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/Simple)
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"simplePatterns12.fs"|])>]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ module SimpleConstant =
|> shouldFail
|> withDiagnostics [
(Warning 3190, Line 13, Col 7, Line 13, Col 17, "Lowercase literal 'intLiteral' is being shadowed by a new pattern with the same name. Only uppercase and module-prefixed literals can be used as named patterns.")
(Warning 26, Line 14, Col 7, Line 14, Col 26, "This rule will never be matched")
(Warning 26, Line 14, Col 7, Line 14, Col 8, "This rule will never be matched")
(Warning 3190, Line 20, Col 7, Line 20, Col 17, "Lowercase literal 'strLiteral' is being shadowed by a new pattern with the same name. Only uppercase and module-prefixed literals can be used as named patterns.")
(Warning 26, Line 21, Col 7, Line 21, Col 26, "This rule will never be matched")
(Warning 26, Line 21, Col 7, Line 21, Col 8, "This rule will never be matched")
(Warning 3190, Line 27, Col 7, Line 27, Col 18, "Lowercase literal 'boolLiteral' is being shadowed by a new pattern with the same name. Only uppercase and module-prefixed literals can be used as named patterns.")
(Warning 26, Line 28, Col 7, Line 28, Col 27, "This rule will never be matched")
(Warning 26, Line 28, Col 7, Line 28, Col 11, "This rule will never be matched")
]

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/SimpleConstant)
Expand All @@ -125,8 +125,8 @@ module SimpleConstant =
|> shouldFail
|> withDiagnostics [
(Warning 25, Line 8, Col 11, Line 8, Col 16, "Incomplete pattern matches on this expression. For example, the value '``some-other-subtype``' may indicate a case not covered by the pattern(s).")
(Warning 26, Line 14, Col 7, Line 14, Col 57, "This rule will never be matched")
(Warning 26, Line 20, Col 7, Line 20, Col 57, "This rule will never be matched")
(Warning 26, Line 14, Col 7, Line 14, Col 24, "This rule will never be matched")
(Warning 26, Line 20, Col 7, Line 20, Col 24, "This rule will never be matched")
]

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/SimpleConstant)
Expand All @@ -146,7 +146,7 @@ module SimpleConstant =
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withSingleDiagnostic (Warning 26, Line 10, Col 7, Line 10, Col 28, "This rule will never be matched")
|> withSingleDiagnostic (Warning 26, Line 10, Col 7, Line 10, Col 8, "This rule will never be matched")

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/SimpleConstant)
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"type_byte.fs"|])>]
Expand Down Expand Up @@ -246,7 +246,7 @@ module SimpleConstant =
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withSingleDiagnostic (Warning 26, Line 10, Col 7, Line 10, Col 26, "This rule will never be matched")
|> withSingleDiagnostic (Warning 26, Line 10, Col 7, Line 10, Col 17, "This rule will never be matched")

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/SimpleConstant)
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes = [|"type_uint16.fs"|])>]
Expand Down Expand Up @@ -292,4 +292,4 @@ module SimpleConstant =
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withSingleDiagnostic (Warning 26, Line 9, Col 7, Line 9, Col 17, "This rule will never be matched")
|> withSingleDiagnostic (Warning 26, Line 9, Col 7, Line 9, Col 8, "This rule will never be matched")
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ module Tuple =
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withSingleDiagnostic (Warning 26, Line 11, Col 7, Line 12, Col 16, "This rule will never be matched")
|> withSingleDiagnostic (Warning 26, Line 11, Col 7, Line 11, Col 14, "This rule will never be matched")

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/Tuple)
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes = [|"W_RedundantPattern02.fs"|])>]
Expand All @@ -53,5 +53,5 @@ module Tuple =
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldFail
|> withSingleDiagnostic (Warning 26, Line 12, Col 28, Line 12, Col 50, "This rule will never be matched")
|> withSingleDiagnostic (Warning 26, Line 12, Col 28, Line 12, Col 29, "This rule will never be matched")

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A of string * int
| B of string * int
| C
let x v =
match v with
| A(a, b) -> ()
| B(a, b) -> ()
| A(a, b) | B(a, b) -> ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A of string * int
| B of string * int
| C
let x v =
match v with
| A(a, b) -> ()
| B(a, b) -> ()
| A(a, b) | B(a, b) as f -> ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type Stuff =
| A
| B
| C

let x v =
match v with
| A -> ""
| A -> false
| C -> ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let v =
match None with
| Some x -> ""
| Some _ -> ""
| None -> ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A
| B
| C
let x v =
match v with
| A -> ""
| A as foo as foo1 -> ""
| _ -> ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A
| B
| C
let x v =
match v with
| A -> ""
| A as foo -> ""
| C -> ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A
| B
| C
let x v z =
match v with
| A -> ""
| A as foo when z > 5 -> ""
| C -> ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A
| B
| C
let x v =
match v with
| A -> ""
| A -> ""
| C -> ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A
| B
| C
let x v =
match v with
| A -> ""
| A as foo as foo1 as foo3 as foo4 -> ""
| _ -> ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A
| B
| C
let x v =
match v with
| A -> ""
| A as foo as foo1 as foo3 as foo4 when foo = A -> ""
| _ -> ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type Stuff =
| A of a: string * b: int
| B
| C
let x v =
match v with
| A(s, i) -> ""
| A(b=i) as foo as foo1 as foo3 as foo4 when i = 0 -> ""
| _ -> ""
Loading