Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0aa662e
TcPat recovery: simple pats
auduchinok Oct 5, 2019
9d15228
TcPat recovery: report union case and active pattern items before che…
auduchinok Oct 5, 2019
d6e3252
TcPat recovery: type check attributes
auduchinok Oct 5, 2019
0c68b3e
TcPat recovery: literal patterns, union case named args
auduchinok Oct 7, 2019
e059203
TcPat recovery: literal patterns, union case args
auduchinok Oct 7, 2019
d630e07
TcPat recovery: active patterns named args
auduchinok Oct 7, 2019
df5fff1
TcPat recovery: union case 2
auduchinok Oct 7, 2019
bb108bb
TcPat recovery: update tests
auduchinok Oct 8, 2019
4624f58
TcPat recovery: different names/types in Or patterns
auduchinok Oct 8, 2019
761c242
Move tests file to common place
auduchinok Oct 8, 2019
40a3017
Fix tupled union case args
auduchinok Oct 8, 2019
69e8abb
Lost change
auduchinok Oct 8, 2019
4747618
Fix test project file include
auduchinok Oct 8, 2019
3007d08
Review fix: use errorRecovery when catching exceptions
auduchinok Oct 29, 2019
dab1d30
Minimize diff
auduchinok Oct 29, 2019
213de15
Minimize diff
auduchinok Oct 29, 2019
2debbc1
Update FCS project analysis test baselines
auduchinok Oct 29, 2019
04e0378
Merge remote-tracking branch 'origin/master' into tcPat-recovery
auduchinok Mar 3, 2020
87b70da
Merge fixes
auduchinok Mar 3, 2020
6de27d8
Update test
auduchinok Mar 3, 2020
49c6774
Fix fsharpqa baselines
auduchinok Mar 4, 2020
ad6bf76
Another fsharpqa baselines update
auduchinok Mar 4, 2020
d28b56e
Update desktop suite baselines
auduchinok Mar 4, 2020
c37f824
Update vsbsl
auduchinok Mar 4, 2020
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\netfx.props" />
<Import Project="..\..\eng\Versions.props"/> <!-- keep our test deps in line with the overall compiler -->
<PropertyGroup>
Expand Down Expand Up @@ -61,6 +61,9 @@
<Compile Include="$(FSharpSourcesRoot)\..\tests\service\TreeVisitorTests.fs">
<Link>TreeVisitorTests.fs</Link>
</Compile>
<Compile Include="$(FSharpSourcesRoot)\..\tests\service\PatternMatchCompilationTests.fs">
<Link>PatternMatchCompilationTests.fs</Link>
</Compile>
<Compile Include="$(FSharpSourcesRoot)\..\tests\service\ScriptOptionsTests.fs">
<Link>ScriptOptionsTests.fs</Link>
</Compile>
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FindUnsolved.fs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ and accDiscrim cenv env d =
| DecisionTreeTest.ActivePatternCase (exp, tys, _, _, _) ->
accExpr cenv env exp
accTypeInst cenv env tys
| DecisionTreeTest.Error _ -> ()

and accAttrib cenv env (Attrib(_, _k, args, props, _, _, _m)) =
args |> List.iter (fun (AttribExpr(expr1, expr2)) ->
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5083,6 +5083,7 @@ and GenDecisionTreeSwitch cenv cgbuf inplabOpt stackAtTargets eenv e cases defau
error(InternalError("non-dense integer matches not implemented in codegen - these should have been removed by the pattern match compiler", switchm))
GenDecisionTreeCases cenv cgbuf stackAtTargets eenv defaultTargetOpt targets repeatSP targetInfos sequel caseLabels cases contf
| _ -> error(InternalError("these matches should never be needed", switchm))
| DecisionTreeTest.Error m -> error(InternalError("Trying to compile error recovery branch", m))

and GenDecisionTreeCases cenv cgbuf stackAtTargets eenv defaultTargetOpt targets repeatSP targetInfos sequel caseLabels cases (contf: Zmap<_,_> -> FakeUnit) =

Expand Down
75 changes: 46 additions & 29 deletions src/fsharp/PatternMatchCompilation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type Pattern =
| TPat_range of char * char * range
| TPat_null of range
| TPat_isinst of TType * TType * PatternValBinding option * range
| TPat_error of range

member this.Range =
match this with
| TPat_const(_, m) -> m
Expand All @@ -61,6 +63,7 @@ type Pattern =
| TPat_range(_, _, m) -> m
| TPat_null m -> m
| TPat_isinst(_, _, _, m) -> m
| TPat_error m -> m

and PatternValBinding = PBind of Val * TypeScheme

Expand Down Expand Up @@ -419,7 +422,11 @@ let getDiscrimOfPattern (g: TcGlobals) tpinst t =
| TPat_array (args, ty, _m) ->
Some(DecisionTreeTest.ArrayLength (args.Length, ty))
| TPat_query ((activePatExpr, resTys, apatVrefOpt, idx, apinfo), _, _m) ->
Some(DecisionTreeTest.ActivePatternCase (activePatExpr, instTypes tpinst resTys, apatVrefOpt, idx, apinfo))
Some (DecisionTreeTest.ActivePatternCase (activePatExpr, instTypes tpinst resTys, apatVrefOpt, idx, apinfo))

| TPat_error range ->
Some (DecisionTreeTest.Error range)

| _ -> None

let constOfDiscrim discrim =
Expand Down Expand Up @@ -459,10 +466,10 @@ let rec chooseSimultaneousEdgeSet prevOpt f l =
| [] -> [], []
| h :: t ->
match f prevOpt h with
| Some x, _ ->
| Some x ->
let l, r = chooseSimultaneousEdgeSet (Some x) f t
x :: l, r
| None, _cont ->
| None ->
let l, r = chooseSimultaneousEdgeSet prevOpt f t
l, h :: r

Expand Down Expand Up @@ -490,6 +497,11 @@ let discrimsHaveSameSimultaneousClass g d1 d2 =

| _ -> false

let canInvestigate (pat: Pattern) =
match pat with
| TPat_null _ | TPat_isinst _ | TPat_exnconstr _ | TPat_unioncase _
| TPat_array _ | TPat_const _ | TPat_query _ | TPat_range _ | TPat_error _ -> true
| _ -> false

/// Decide the next pattern to investigate
let ChooseInvestigationPointLeftToRight frontiers =
Expand All @@ -498,8 +510,7 @@ let ChooseInvestigationPointLeftToRight frontiers =
let rec choose l =
match l with
| [] -> failwith "ChooseInvestigationPointLeftToRight: no non-immediate patterns in first rule"
| (Active(_, _, (TPat_null _ | TPat_isinst _ | TPat_exnconstr _ | TPat_unioncase _ | TPat_array _ | TPat_const _ | TPat_query _ | TPat_range _)) as active)
:: _ -> active
| Active (_, _, pat) as active :: _ when canInvestigate pat -> active
| _ :: t -> choose t
choose actives
| [] -> failwith "ChooseInvestigationPointLeftToRight: no frontiers!"
Expand Down Expand Up @@ -698,6 +709,7 @@ let rec isPatternPartial p =
| TPat_range _ -> false
| TPat_null _ -> false
| TPat_isinst _ -> false
| TPat_error _ -> false

let rec erasePartialPatterns inpp =
match inpp with
Expand All @@ -716,7 +728,8 @@ let rec erasePartialPatterns inpp =
| TPat_wild _
| TPat_range _
| TPat_null _
| TPat_isinst _ -> inpp
| TPat_isinst _
| TPat_error _ -> inpp

and erasePartials inps =
List.map erasePartialPatterns inps
Expand All @@ -736,14 +749,14 @@ let CompilePatternBasic
warnOnIncomplete
actionOnFailure
(origInputVal, origInputValTypars, _origInputExprOpt: Expr option)
(clausesL: TypedMatchClause list)
(typedClauses: TypedMatchClause list)
inputTy
resultTy =
// Add the targets to a match builder.
// Note the input expression has already been evaluated and saved into a variable,
// hence no need for a new sequence point.
let matchBuilder = MatchBuilder (NoSequencePointAtInvisibleBinding, exprm)
clausesL |> List.iter (fun c -> matchBuilder.AddTarget c.Target |> ignore)
typedClauses |> List.iter (fun c -> matchBuilder.AddTarget c.Target |> ignore)

// Add the incomplete or rethrow match clause on demand,
// printing a warning if necessary (only if it is ever exercised).
Expand Down Expand Up @@ -807,8 +820,8 @@ let CompilePatternBasic
| Some c -> c

// Helpers to get the variables bound at a target.
// We conceptually add a dummy clause that will always succeed with a "throw"
let clausesA = Array.ofList clausesL
// We conceptually add a dummy clause that will always succeed with a "throw".
let clausesA = Array.ofList typedClauses
let nClauses = clausesA.Length
let GetClause i refuted =
if i < nClauses then
Expand Down Expand Up @@ -842,14 +855,10 @@ let CompilePatternBasic
| _ ->
// Otherwise choose a point (i.e. a path) to investigate.
let (Active(path, subexpr, pat)) = ChooseInvestigationPointLeftToRight frontiers
match pat with
// All these constructs should have been eliminated in BindProjectionPattern
| TPat_as _ | TPat_tuple _ | TPat_wild _ | TPat_disjs _ | TPat_conjs _ | TPat_recd _ ->
if not (canInvestigate pat) then
// All these constructs should have been eliminated in BindProjectionPattern
failwith "Unexpected pattern"

// Leaving the ones where we have real work to do.
| _ ->

else
let simulSetOfEdgeDiscrims, fallthroughPathFrontiers = ChooseSimultaneousEdges frontiers path

let inpExprOpt, bindOpt = ChoosePreBinder simulSetOfEdgeDiscrims subexpr
Expand All @@ -861,8 +870,7 @@ let CompilePatternBasic

// Work out what the default/fall-through tree looks like, is any
// Check if match is complete, if so optimize the default case away.

let defaultTreeOpt : DecisionTree option = CompileFallThroughTree fallthroughPathFrontiers path refuted simulSetOfCases
let defaultTreeOpt = CompileFallThroughTree fallthroughPathFrontiers path refuted simulSetOfCases

// OK, build the whole tree and whack on the binding if any
let finalDecisionTree =
Expand All @@ -879,7 +887,7 @@ let CompilePatternBasic
let es2 =
vs2 |> List.map (fun v ->
match valMap.TryFind v with
| None -> error(Error(FSComp.SR.patcMissingVariable(v.DisplayName), v.Range))
| None -> mkUnit g v.Range
| Some res -> res)
let rhs' = TDSuccess(es2, i)
match GetWhenGuardOfClause i refuted with
Expand Down Expand Up @@ -913,14 +921,14 @@ let CompilePatternBasic
match getDiscrimOfPattern p with
| Some discrim ->
if (match prevOpt with None -> true | Some (EdgeDiscrim(_, discrimPrev, _)) -> discrimsHaveSameSimultaneousClass g discrim discrimPrev) then
Some (EdgeDiscrim(i', discrim, p.Range)), true
Some (EdgeDiscrim(i', discrim, p.Range))
else
None, false
None

| None ->
None, true
None
else
None, true)
None)

and IsCopyableInputExpr origInputExpr =
match origInputExpr with
Expand Down Expand Up @@ -1235,8 +1243,17 @@ let CompilePatternBasic
| _ ->
[frontier]

| TPat_error range ->
match discrim with
| DecisionTreeTest.Error testRange when range = testRange ->
[Frontier (i, active', valMap)]
| _ ->
[frontier]

| _ -> failwith "pattern compilation: GenerateNewFrontiersAfterSuccessfulInvestigation"
else [frontier]

else
[frontier]

and BindProjectionPattern (Active(path, subExpr, p) as inp) ((accActive, accValMap) as s) =
let (SubExpr(accessf, ve)) = subExpr
Expand Down Expand Up @@ -1286,11 +1303,11 @@ let CompilePatternBasic
and BindProjectionPatterns ps s =
List.foldBack (fun p sofar -> List.collect (BindProjectionPattern p) sofar) ps [s]

(* The setup routine of the match compiler *)
// The setup routine of the match compiler.
let frontiers =
((clausesL
((typedClauses
|> List.mapi (fun i c ->
let initialSubExpr = SubExpr((fun _tpinst x -> x), (exprForVal origInputVal.Range origInputVal, origInputVal))
let initialSubExpr = SubExpr((fun _ x -> x), (exprForVal origInputVal.Range origInputVal, origInputVal))
let investigations = BindProjectionPattern (Active(PathEmpty inputTy, initialSubExpr, c.Pattern)) ([], ValMap<_>.Empty)
mkFrontiers investigations i)
|> List.concat)
Expand All @@ -1308,7 +1325,7 @@ let CompilePatternBasic
if warnOnUnused then
let used = HashSet<_>(accTargetsOfDecisionTree dtree [], HashIdentity.Structural)

clausesL |> List.iteri (fun i c ->
typedClauses |> List.iteri (fun i c ->
if not (used.Contains i) then warning (RuleNeverMatched c.Range))

dtree, targets
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/PatternMatchCompilation.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Pattern =
| TPat_range of char * char * range
| TPat_null of range
| TPat_isinst of TType * TType * PatternValBinding option * range
| TPat_error of range

member Range: range

Expand Down
1 change: 1 addition & 0 deletions src/fsharp/PostInferenceChecks.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,7 @@ and CheckDecisionTreeTest cenv env m discrim =
| DecisionTreeTest.IsNull -> ()
| DecisionTreeTest.IsInst (srcTy, tgtTy) -> CheckTypeNoInnerByrefs cenv env m srcTy; CheckTypeNoInnerByrefs cenv env m tgtTy
| DecisionTreeTest.ActivePatternCase (exp, _, _, _, _) -> CheckExprNoByrefs cenv env exp
| DecisionTreeTest.Error _ -> ()

and CheckAttrib cenv env (Attrib(_, _, args, props, _, _, _)) =
props |> List.iter (fun (AttribNamedArg(_, _, _, expr)) -> CheckAttribExpr cenv env expr)
Expand Down
2 changes: 2 additions & 0 deletions src/fsharp/QuotationTranslator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,8 @@ and ConvDecisionTree cenv env tgs typR x =
| DecisionTreeTest.ActivePatternCase _ -> wfail(InternalError( "DecisionTreeTest.ActivePatternCase test in quoted expression", m))

| DecisionTreeTest.ArrayLength _ -> wfail(Error(FSComp.SR.crefQuotationsCantContainArrayPatternMatching(), m))

| DecisionTreeTest.Error m -> wfail(InternalError( "DecisionTreeTest.Error in quoted expression", m))
)
EmitDebugInfoIfNecessary cenv env m converted

Expand Down
3 changes: 3 additions & 0 deletions src/fsharp/TastOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3944,6 +3944,7 @@ module DebugPrint =
| (DecisionTreeTest.IsNull ) -> wordL(tagText "isnull")
| (DecisionTreeTest.IsInst (_, ty)) -> wordL(tagText "isinst") ^^ typeL ty
| (DecisionTreeTest.ActivePatternCase (exp, _, _, _, _)) -> wordL(tagText "query") ^^ exprL g exp
| (DecisionTreeTest.Error _) -> wordL (tagText "error recovery")

and targetL g i (TTarget (argvs, body, _)) = leftL(tagText "T") ^^ intL i ^^ tupleL (flatValsL argvs) ^^ rightL(tagText ":") --- exprL g body

Expand Down Expand Up @@ -4421,6 +4422,7 @@ and accFreeInTest (opts: FreeVarOptions) discrim acc =
accFreeInExpr opts exp
(accFreeVarsInTys opts tys
(Option.foldBack (fun (vref, tinst) acc -> accFreeValRef opts vref (accFreeVarsInTys opts tinst acc)) activePatIdentity acc))
| DecisionTreeTest.Error _ -> acc

and accFreeInDecisionTree opts x (acc: FreeVars) =
match x with
Expand Down Expand Up @@ -5227,6 +5229,7 @@ and remapDecisionTree g compgen tmenv x =
| DecisionTreeTest.IsInst (srcty, tgty) -> DecisionTreeTest.IsInst (remapType tmenv srcty, remapType tmenv tgty)
| DecisionTreeTest.IsNull -> DecisionTreeTest.IsNull
| DecisionTreeTest.ActivePatternCase _ -> failwith "DecisionTreeTest.ActivePatternCase should only be used during pattern match compilation"
| DecisionTreeTest.Error _ -> failwith "DecisionTreeTest.Error should only be used during pattern match compilation"
TCase(test', remapDecisionTree g compgen tmenv y)) csl,
Option.map (remapDecisionTree g compgen tmenv) dflt,
m)
Expand Down
3 changes: 2 additions & 1 deletion src/fsharp/TastPickle.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2397,7 +2397,8 @@ and p_dtree_discrim x st =
| DecisionTreeTest.IsNull -> p_byte 2 st
| DecisionTreeTest.IsInst (srcty, tgty) -> p_byte 3 st; p_ty srcty st; p_ty tgty st
| DecisionTreeTest.ArrayLength (n, ty) -> p_byte 4 st; p_tup2 p_int p_ty (n, ty) st
| DecisionTreeTest.ActivePatternCase _ -> pfailwith st "DecisionTreeTest.ActivePatternCase: only used during pattern match compilation"
| DecisionTreeTest.ActivePatternCase _ -> pfailwith st "DecisionTreeTest.ActivePatternCase: only used during pattern match compilation"
| DecisionTreeTest.Error _ -> pfailwith st "DecisionTreeTest.Error: only used during pattern match compilation"

and p_target (TTarget(a, b, _)) st = p_tup2 p_Vals p_expr (a, b) st
and p_bind (TBind(a, b, _)) st = p_tup2 p_Val p_expr (a, b) st
Expand Down
Loading