@@ -30,7 +30,6 @@ type ActionOnFailure =
3030 | FailFilter
3131
3232[<NoEquality; NoComparison>]
33- /// Represents type-checked patterns
3433type Pattern =
3534 | TPat_ const of Const * range
3635 | TPat_ wild of range (* note = TPat_disjs([], m), but we haven't yet removed that duplication *)
@@ -720,7 +719,9 @@ let rec erasePartialPatterns inpp =
720719 | TPat_ range _
721720 | TPat_ null _
722721 | TPat_ isinst _ -> inpp
723- and erasePartials inps = List.map erasePartialPatterns inps
722+
723+ and erasePartials inps =
724+ List.map erasePartialPatterns inps
724725
725726
726727//---------------------------------------------------------------------------
@@ -740,118 +741,115 @@ let CompilePatternBasic
740741 ( clausesL : TypedMatchClause list )
741742 inputTy
742743 resultTy =
743- // Add the targets to a match builder
744- // Note the input expression has already been evaluated and saved into a variable.
745- // Hence no need for a new sequence point.
746- let mbuilder = new MatchBuilder( NoSequencePointAtInvisibleBinding, exprm)
747- clausesL |> List.iteri ( fun _i c -> mbuilder .AddTarget c.Target |> ignore)
748-
749- // Add the incomplete or rethrow match clause on demand, printing a
750- // warning if necessary (only if it is ever exercised)
751- let incompleteMatchClauseOnce = ref None
744+ // Add the targets to a match builder.
745+ // Note the input expression has already been evaluated and saved into a variable,
746+ // hence no need for a new sequence point.
747+ let matchBuilder = MatchBuilder ( NoSequencePointAtInvisibleBinding, exprm)
748+ clausesL |> List.iter ( fun c -> matchBuilder .AddTarget c.Target |> ignore)
749+
750+ // Add the incomplete or rethrow match clause on demand,
751+ // printing a warning if necessary (only if it is ever exercised).
752+ let mutable incompleteMatchClauseOnce = None
752753 let getIncompleteMatchClause refuted =
753- // This is lazy because emit a
754- // warning when the lazy thunk gets evaluated
755- match ! incompleteMatchClauseOnce with
754+ // This is lazy because emit a warning when the lazy thunk gets evaluated.
755+ match incompleteMatchClauseOnce with
756756 | None ->
757- (* Emit the incomplete match warning *)
758- if warnOnIncomplete then
759- match actionOnFailure with
760- | ThrowIncompleteMatchException | IgnoreWithWarning ->
761- let ignoreWithWarning = ( actionOnFailure = IgnoreWithWarning)
762- match ShowCounterExample g denv matchm refuted with
763- | Some( text, failingWhenClause, true ) ->
764- warning ( EnumMatchIncomplete( ignoreWithWarning, Some( text, failingWhenClause), matchm))
765- | Some( text, failingWhenClause, false ) ->
766- warning ( MatchIncomplete( ignoreWithWarning, Some( text, failingWhenClause), matchm))
767- | None ->
768- warning ( MatchIncomplete( ignoreWithWarning, None, matchm))
769- | _ ->
770- ()
771-
772- let throwExpr =
773- match actionOnFailure with
774- | FailFilter ->
775- // Return 0 from the .NET exception filter
776- mkInt g matchm 0
777-
778- | Rethrow ->
779- // Rethrow unmatched try-catch exn. No sequence point at the target since its not
780- // real code.
781- mkReraise matchm resultTy
782-
783- | Throw ->
784- // We throw instead of rethrow on unmatched try-catch in a computation expression. But why?
785- // Because this isn't a real .NET exception filter/handler but just a function we're passing
786- // to a computation expression builder to simulate one.
787- mkThrow matchm resultTy ( exprForVal matchm origInputVal)
788-
789- | ThrowIncompleteMatchException ->
790- mkThrow matchm resultTy
791- ( mkExnExpr( mk_ MFCore_ tcref g.fslibCcu " MatchFailureException" ,
792- [ mkString g matchm matchm.FileName
793- mkInt g matchm matchm.StartLine
794- mkInt g matchm matchm.StartColumn], matchm))
795-
796- | IgnoreWithWarning ->
797- mkUnit g matchm
798-
799- // We don't emit a sequence point at any of the above cases because they don't correspond to
800- // user code.
801- //
802- // Note we don't emit sequence points at either the succeeding or failing
803- // targets of filters since if the exception is filtered successfully then we
804- // will run the handler and hit the sequence point there.
805- // That sequence point will have the pattern variables bound, which is exactly what we want.
806- let tg = TTarget( List.empty, throwExpr, SuppressSequencePointAtTarget )
807- mbuilder.AddTarget tg |> ignore
808- let clause = TClause( TPat_ wild matchm, None, tg, matchm)
809- incompleteMatchClauseOnce := Some clause
810- clause
757+ // Emit the incomplete match warning.
758+ if warnOnIncomplete then
759+ match actionOnFailure with
760+ | ThrowIncompleteMatchException | IgnoreWithWarning ->
761+ let ignoreWithWarning = ( actionOnFailure = IgnoreWithWarning)
762+ match ShowCounterExample g denv matchm refuted with
763+ | Some( text, failingWhenClause, true ) ->
764+ warning ( EnumMatchIncomplete( ignoreWithWarning, Some( text, failingWhenClause), matchm))
765+ | Some( text, failingWhenClause, false ) ->
766+ warning ( MatchIncomplete( ignoreWithWarning, Some( text, failingWhenClause), matchm))
767+ | None ->
768+ warning ( MatchIncomplete( ignoreWithWarning, None, matchm))
769+ | _ ->
770+ ()
771+
772+ let throwExpr =
773+ match actionOnFailure with
774+ | FailFilter ->
775+ // Return 0 from the .NET exception filter.
776+ mkInt g matchm 0
777+
778+ | Rethrow ->
779+ // Rethrow unmatched try-catch exn. No sequence point at the target since its not real code.
780+ mkReraise matchm resultTy
781+
782+ | Throw ->
783+ // We throw instead of rethrow on unmatched try-catch in a computation expression. But why?
784+ // Because this isn't a real .NET exception filter/handler but just a function we're passing
785+ // to a computation expression builder to simulate one.
786+ mkThrow matchm resultTy ( exprForVal matchm origInputVal)
787+
788+ | ThrowIncompleteMatchException ->
789+ mkThrow matchm resultTy
790+ ( mkExnExpr( mk_ MFCore_ tcref g.fslibCcu " MatchFailureException" ,
791+ [ mkString g matchm matchm.FileName
792+ mkInt g matchm matchm.StartLine
793+ mkInt g matchm matchm.StartColumn], matchm))
794+
795+ | IgnoreWithWarning ->
796+ mkUnit g matchm
797+
798+ // We don't emit a sequence point at any of the above cases because they don't correspond to user code.
799+ //
800+ // Note we don't emit sequence points at either the succeeding or failing targets of filters since if
801+ // the exception is filtered successfully then we will run the handler and hit the sequence point there.
802+ // That sequence point will have the pattern variables bound, which is exactly what we want.
803+ let tg = TTarget( List.empty, throwExpr, SuppressSequencePointAtTarget)
804+ let _ = matchBuilder.AddTarget tg
805+ let clause = TClause( TPat_ wild matchm, None, tg, matchm)
806+ incompleteMatchClauseOnce <- Some clause
807+ clause
811808
812809 | Some c -> c
813810
814- // Helpers to get the variables bound at a target. We conceptually add a dummy clause that will always succeed with a "throw"
811+ // Helpers to get the variables bound at a target.
812+ // We conceptually add a dummy clause that will always succeed with a "throw"
815813 let clausesA = Array.ofList clausesL
816- let nclauses = clausesA.Length
814+ let nClauses = clausesA.Length
817815 let GetClause i refuted =
818- if i < nclauses then
816+ if i < nClauses then
819817 clausesA.[ i]
820- elif i = nclauses then getIncompleteMatchClause refuted
818+ elif i = nClauses then getIncompleteMatchClause refuted
821819 else failwith " GetClause"
822820 let GetValsBoundByClause i refuted = ( GetClause i refuted) .BoundVals
823821 let GetWhenGuardOfClause i refuted = ( GetClause i refuted) .GuardExpr
824822
825- // Different uses of parameterized active patterns have different identities as far as paths
826- // are concerned. Here we generate unique numbers that are completely different to any stamp
827- // by usig negative numbers.
823+ // Different uses of parameterized active patterns have different identities as far as paths are concerned.
824+ // Here we generate unique numbers that are completely different to any stamp by using negative numbers.
828825 let genUniquePathId () = - ( newUnique())
829826
830- // Build versions of these functions which apply a dummy instantiation to the overall type arguments
827+ // Build versions of these functions which apply a dummy instantiation to the overall type arguments.
831828 let GetSubExprOfInput , getDiscrimOfPattern =
832829 let tyargs = List.map ( fun _ -> g.unit_ ty) origInputValTypars
833830 let unit_tpinst = mkTyparInst origInputValTypars tyargs
834831 GetSubExprOfInput g ( origInputValTypars, tyargs, unit_ tpinst),
835832 getDiscrimOfPattern g unit_ tpinst
836833
837- // The main recursive loop of the pattern match compiler
834+ // The main recursive loop of the pattern match compiler.
838835 let rec InvestigateFrontiers refuted frontiers =
839836 match frontiers with
840837 | [] -> failwith " CompilePattern: compile - empty clauses: at least the final clause should always succeed"
841- | ( Frontier ( i, active, valMap) ) :: rest ->
838+ | Frontier ( i, active, valMap) :: rest ->
842839
843- // Check to see if we've got a succeeding clause. There may still be a 'when' condition for the clause
840+ // Check to see if we've got a succeeding clause. There may still be a 'when' condition for the clause.
844841 match active with
845842 | [] -> CompileSuccessPointAndGuard i refuted valMap rest
846843
847844 | _ ->
848- (* Otherwise choose a point (i.e. a path) to investigate. *)
845+ // Otherwise choose a point (i.e. a path) to investigate.
849846 let ( Active ( path , subexpr , pat )) = ChooseInvestigationPointLeftToRight frontiers
850847 match pat with
851848 // All these constructs should have been eliminated in BindProjectionPattern
852- | TPat_ as _ | TPat_ tuple _ | TPat_ wild _ | TPat_ disjs _ | TPat_ conjs _ | TPat_ recd _ -> failwith " Unexpected pattern"
849+ | TPat_ as _ | TPat_ tuple _ | TPat_ wild _ | TPat_ disjs _ | TPat_ conjs _ | TPat_ recd _ ->
850+ failwith " Unexpected pattern"
853851
854- // Leaving the ones where we have real work to do
852+ // Leaving the ones where we have real work to do.
855853 | _ ->
856854
857855 let simulSetOfEdgeDiscrims , fallthroughPathFrontiers = ChooseSimultaneousEdges frontiers path
@@ -879,7 +877,6 @@ let CompilePatternBasic
879877 finalDecisionTree
880878
881879 and CompileSuccessPointAndGuard i refuted valMap rest =
882-
883880 let vs2 = GetValsBoundByClause i refuted
884881 let es2 =
885882 vs2 |> List.map ( fun v ->
@@ -907,25 +904,25 @@ let CompilePatternBasic
907904
908905 | None -> rhs'
909906
910- /// Select the set of discriminators which we can handle in one test, or as a series of
911- /// iterated tests, e.g. in the case of TPat_isinst. Ensure we only take at most one class of `TPat_query` at a time.
907+ /// Select the set of discriminators which we can handle in one test, or as a series of iterated tests,
908+ /// e.g. in the case of TPat_isinst. Ensure we only take at most one class of `TPat_query` at a time.
912909 /// Record the rule numbers so we know which rule the TPat_query cam from, so that when we project through
913910 /// the frontier we only project the right rule.
914911 and ChooseSimultaneousEdges frontiers path =
915912 frontiers |> chooseSimultaneousEdgeSet None ( fun prevOpt ( Frontier ( i' , active' , _ )) ->
916- if isMemOfActives path active' then
917- let p = lookupActive path active' |> snd
918- match getDiscrimOfPattern p with
919- | Some discrim ->
920- if ( match prevOpt with None -> true | Some ( EdgeDiscrim(_, discrimPrev, _)) -> discrimsHaveSameSimultaneousClass g discrim discrimPrev) then
921- Some ( EdgeDiscrim( i', discrim, p.Range)), true
922- else
923- None, false
924-
925- | None ->
926- None, true
927- else
928- None, true )
913+ if isMemOfActives path active' then
914+ let _ , p = lookupActive path active'
915+ match getDiscrimOfPattern p with
916+ | Some discrim ->
917+ if ( match prevOpt with None -> true | Some ( EdgeDiscrim(_, discrimPrev, _)) -> discrimsHaveSameSimultaneousClass g discrim discrimPrev) then
918+ Some ( EdgeDiscrim( i', discrim, p.Range)), true
919+ else
920+ None, false
921+
922+ | None ->
923+ None, true
924+ else
925+ None, true )
929926
930927 and IsCopyableInputExpr origInputExpr =
931928 match origInputExpr with
@@ -1298,13 +1295,13 @@ let CompilePatternBasic
12981295 mkFrontiers investigations i)
12991296 |> List.concat)
13001297 @
1301- mkFrontiers [([], ValMap<_>. Empty)] nclauses )
1298+ mkFrontiers [([], ValMap<_>. Empty)] nClauses )
13021299 let dtree =
13031300 InvestigateFrontiers
13041301 []
13051302 frontiers
13061303
1307- let targets = mbuilder .CloseTargets()
1304+ let targets = matchBuilder .CloseTargets()
13081305
13091306
13101307 // Report unused targets
@@ -1320,33 +1317,32 @@ let isPartialOrWhenClause (c: TypedMatchClause) = isPatternPartial c.Pattern ||
13201317
13211318
13221319let rec CompilePattern g denv amap exprm matchm warnOnUnused actionOnFailure ( origInputVal , origInputValTypars , origInputExprOpt ) ( clausesL : TypedMatchClause list ) inputTy resultTy =
1323- match clausesL with
1324- | _ when List.exists isPartialOrWhenClause clausesL ->
1320+ match clausesL with
1321+ | _ when List.exists isPartialOrWhenClause clausesL ->
13251322 // Partial clauses cause major code explosion if treated naively
13261323 // Hence treat any pattern matches with any partial clauses clause-by-clause
13271324
13281325 // First make sure we generate at least some of the obvious incomplete match warnings.
1329- let warnOnUnused = false in (* we can't turn this on since we're pretending all partial's fail in order to control the complexity of this. *)
1326+ let warnOnUnused = false // we can't turn this on since we're pretending all partials fail in order to control the complexity of this.
13301327 let warnOnIncomplete = true
13311328 let clausesPretendAllPartialFail = List.collect ( fun ( TClause ( p , whenOpt , tg , m )) -> [ TClause( erasePartialPatterns p, whenOpt, tg, m)]) clausesL
13321329 let _ = CompilePatternBasic g denv amap exprm matchm warnOnUnused warnOnIncomplete actionOnFailure ( origInputVal, origInputValTypars, origInputExprOpt) clausesPretendAllPartialFail inputTy resultTy
13331330 let warnOnIncomplete = false
13341331
13351332 let rec atMostOnePartialAtATime clauses =
13361333 match List.takeUntil isPartialOrWhenClause clauses with
1337- | l, [] ->
1334+ | l, [] ->
13381335 CompilePatternBasic g denv amap exprm matchm warnOnUnused warnOnIncomplete actionOnFailure ( origInputVal, origInputValTypars, origInputExprOpt) l inputTy resultTy
13391336 | l, ( h :: t) ->
1340- // Add the partial clause
1337+ // Add the partial clause.
13411338 doGroupWithAtMostOnePartial ( l @ [ h]) t
13421339
13431340 and doGroupWithAtMostOnePartial group rest =
1341+ // Compile the remaining clauses.
1342+ let decisionTree , targets = atMostOnePartialAtATime rest
13441343
1345- // Compile the remaining clauses
1346- let dtree , targets = atMostOnePartialAtATime rest
1347-
1348- // Make the expression that represents the remaining cases of the pattern match
1349- let expr = mkAndSimplifyMatch NoSequencePointAtInvisibleBinding exprm matchm resultTy dtree targets
1344+ // Make the expression that represents the remaining cases of the pattern match.
1345+ let expr = mkAndSimplifyMatch NoSequencePointAtInvisibleBinding exprm matchm resultTy decisionTree targets
13501346
13511347 // If the remainder of the match boiled away to nothing interesting.
13521348 // We measure this simply by seeing if the range of the resulting expression is identical to matchm.
@@ -1362,5 +1358,5 @@ let rec CompilePattern g denv amap exprm matchm warnOnUnused actionOnFailure (o
13621358
13631359 atMostOnePartialAtATime clausesL
13641360
1365- | _ ->
1366- CompilePatternBasic g denv amap exprm matchm warnOnUnused true actionOnFailure ( origInputVal, origInputValTypars, origInputExprOpt) clausesL inputTy resultTy
1361+ | _ ->
1362+ CompilePatternBasic g denv amap exprm matchm warnOnUnused true actionOnFailure ( origInputVal, origInputValTypars, origInputExprOpt) clausesL inputTy resultTy
0 commit comments