@@ -3789,18 +3789,70 @@ and GenTry cenv cgbuf eenv scopeMarks (e1, m, resultTy, spTry) =
37893789 let tryMarks = ( startTryMark.CodeLabel, endTryMark.CodeLabel)
37903790 whereToSaveOpt, eenvinner, stack, tryMarks, afterHandler
37913791
3792- and GenTryWith cenv cgbuf eenv ( e1 , vf : Val , ef , vh : Val , eh , m , resty , spTry , spWith ) sequel =
3792+ /// Determine if a filter block is side-effect free, meaning it can be run on the first pass and
3793+ /// the pattern match logic repeated on the second pass.
3794+ ///
3795+ /// Filter blocks are only ever generated by pattern match compilation so we can safely look for particular
3796+ /// constructs.
3797+ and eligibleForFilter ( cenv : cenv ) expr =
3798+ let rec check expr =
3799+ match expr with
3800+ | Expr.Let ( TBind(_, be, _), body, _, _) ->
3801+ check be && check body
3802+ | Expr.DebugPoint(_, expr) -> check expr
3803+ | Expr.Match (_ spBind, _ exprm, dtree, targets, _, _) ->
3804+ checkDecisionTree dtree &&
3805+ targets |> Array.forall ( fun ( TTarget ( _ , e , _ )) -> check e)
3806+ | Expr.Const _ -> true
3807+ | Expr.Op( TOp.ILAsm([ I_ isinst _ ], _), _, _, _) -> true
3808+ | Expr.Op( TOp.UnionCaseTagGet _, _, _, _) -> true
3809+ | Expr.Op( TOp.ExnFieldGet _, _, _, _) -> true
3810+ | Expr.Op( TOp.UnionCaseFieldGet _, _, _, _) -> true
3811+ | Expr.Op( TOp.ValFieldGet _, _, _, _) -> true
3812+ | Expr.Op( TOp.TupleFieldGet _, _, _, _) -> true
3813+ | Expr.Op( TOp.Coerce _, _, _, _) -> true
3814+ | Expr.Val _ -> true
3815+ | _ -> false
3816+ and checkDecisionTree dtree =
3817+ match dtree with
3818+ | TDSwitch( ve, cases, dflt, _) ->
3819+ check ve &&
3820+ cases |> List.forall checkDecisionTreeCase &&
3821+ dflt |> Option.forall checkDecisionTree
3822+ | TDSuccess ( es, _) -> es |> List.forall check
3823+ | TDBind( bind, rest) -> check bind.Expr && checkDecisionTree rest
3824+ and checkDecisionTreeCase dcase =
3825+ let ( TCase ( test , tree )) = dcase
3826+ checkDecisionTree tree &&
3827+ match test with
3828+ | DecisionTreeTest.UnionCase _ -> true
3829+ | DecisionTreeTest.ArrayLength _ -> true
3830+ | DecisionTreeTest.Const _ -> true
3831+ | DecisionTreeTest.IsNull -> true
3832+ | DecisionTreeTest.IsInst _ -> true
3833+ | DecisionTreeTest.ActivePatternCase _ -> false // must only be run once
3834+ | DecisionTreeTest.Error _ -> false
3835+
3836+ let isTrivial =
3837+ match expr with
3838+ | DebugPoints ( Expr.Const _, _) -> true
3839+ | _ -> false
3840+
3841+ // Filters seem to generate invalid code for the ilreflect.fs backend
3842+ ( cenv.opts.ilxBackend = IlxGenBackend.IlWriteBackend) &&
3843+ not isTrivial &&
3844+ check expr
3845+
3846+ and GenTryWith cenv cgbuf eenv ( e1 , valForFilter : Val , filterExpr , valForHandler : Val , handlerExpr , m , resty , spTry , spWith ) sequel =
37933847 let g = cenv.g
37943848
37953849 // Save the stack - gross because IL flushes the stack at the exn. handler
37963850 // note: eenvinner notes spill vars are live
37973851 LocalScope " trystack" cgbuf ( fun scopeMarks ->
37983852 let whereToSaveOpt , eenvinner , stack , tryMarks , afterHandler = GenTry cenv cgbuf eenv scopeMarks ( e1, m, resty, spTry)
37993853
3800- // Now the filter and catch blocks
3801-
38023854 let seh =
3803- if cenv.opts.generateFilterBlocks then
3855+ if cenv.opts.generateFilterBlocks || eligibleForFilter cenv filterExpr then
38043856 let startOfFilter = CG.GenerateMark cgbuf " startOfFilter"
38053857 let afterFilter = CG.GenerateDelayMark cgbuf " afterFilter"
38063858 let sequelOnBranches , afterJoin , stackAfterJoin , sequelAfterJoin = GenJoinPoint cenv cgbuf " filter" eenv g.int_ ty m EndFilter
@@ -3819,14 +3871,14 @@ and GenTryWith cenv cgbuf eenv (e1, vf: Val, ef, vh: Val, eh, m, resty, spTry, s
38193871 | DebugPointAtWith.No -> ()
38203872
38213873 CG.SetStack cgbuf [ g.ilg.typ_ Object]
3822- let _ , eenvinner = AllocLocalVal cenv cgbuf vf eenvinner None ( startOfFilter, afterFilter)
3874+ let _ , eenvinner = AllocLocalVal cenv cgbuf valForFilter eenvinner None ( startOfFilter, afterFilter)
38233875 CG.EmitInstr cgbuf ( pop 1 ) ( Push [ g.iltyp_ Exception]) ( I_ castclass g.iltyp_ Exception)
38243876
3825- GenStoreVal cenv cgbuf eenvinner vf .Range vf
3877+ GenStoreVal cenv cgbuf eenvinner valForFilter .Range valForFilter
38263878
38273879 // Why SPSuppress? Because we do not emit a debug point at the start of the List.filter - we've already put one on
38283880 // the 'with' keyword above
3829- GenExpr cenv cgbuf eenvinner ef sequelOnBranches
3881+ GenExpr cenv cgbuf eenvinner filterExpr sequelOnBranches
38303882 CG.SetMarkToHere cgbuf afterJoin
38313883 CG.SetStack cgbuf stackAfterJoin
38323884 GenSequel cenv eenv.cloc cgbuf sequelAfterJoin
@@ -3837,12 +3889,12 @@ and GenTryWith cenv cgbuf eenv (e1, vf: Val, ef, vh: Val, eh, m, resty, spTry, s
38373889 let startOfHandler = CG.GenerateMark cgbuf " startOfHandler"
38383890
38393891 CG.SetStack cgbuf [ g.ilg.typ_ Object]
3840- let _ , eenvinner = AllocLocalVal cenv cgbuf vh eenvinner None ( startOfHandler, afterHandler)
3892+ let _ , eenvinner = AllocLocalVal cenv cgbuf valForHandler eenvinner None ( startOfHandler, afterHandler)
38413893 CG.EmitInstr cgbuf ( pop 1 ) ( Push [ g.iltyp_ Exception]) ( I_ castclass g.iltyp_ Exception)
3842- GenStoreVal cenv cgbuf eenvinner vh .Range vh
3894+ GenStoreVal cenv cgbuf eenvinner valForHandler .Range valForHandler
38433895
38443896 let exitSequel = LeaveHandler ( false , whereToSaveOpt, afterHandler, true )
3845- GenExpr cenv cgbuf eenvinner eh exitSequel
3897+ GenExpr cenv cgbuf eenvinner handlerExpr exitSequel
38463898
38473899 let endOfHandler = CG.GenerateMark cgbuf " endOfHandler"
38483900 let handlerMarks = ( startOfHandler.CodeLabel, endOfHandler.CodeLabel)
@@ -3855,14 +3907,14 @@ and GenTryWith cenv cgbuf eenv (e1, vf: Val, ef, vh: Val, eh, m, resty, spTry, s
38553907 | DebugPointAtWith.No -> ()
38563908
38573909 CG.SetStack cgbuf [ g.ilg.typ_ Object]
3858- let _ , eenvinner = AllocLocalVal cenv cgbuf vh eenvinner None ( startOfHandler, afterHandler)
3910+ let _ , eenvinner = AllocLocalVal cenv cgbuf valForHandler eenvinner None ( startOfHandler, afterHandler)
38593911 CG.EmitInstr cgbuf ( pop 1 ) ( Push [ g.iltyp_ Exception]) ( I_ castclass g.iltyp_ Exception)
38603912
3861- GenStoreVal cenv cgbuf eenvinner m vh
3913+ GenStoreVal cenv cgbuf eenvinner m valForHandler
38623914
38633915 let exitSequel = LeaveHandler ( false , whereToSaveOpt, afterHandler, true )
38643916 let eenvinner = { eenvinner with exitSequel = exitSequel }
3865- GenExpr cenv cgbuf eenvinner eh exitSequel
3917+ GenExpr cenv cgbuf eenvinner handlerExpr exitSequel
38663918
38673919 let endOfHandler = CG.GenerateMark cgbuf " endOfHandler"
38683920 let handlerMarks = ( startOfHandler.CodeLabel, endOfHandler.CodeLabel)
@@ -7709,8 +7761,10 @@ and GenAbstractBinding cenv eenv tref (vref: ValRef) =
77097761 else
77107762 [], [], []
77117763
7712- /// Generate a ToString method that calls 'sprintf "%A"'
7713- and GenToStringMethod cenv eenv ilThisTy m =
7764+ and GenToStringMethod cenv eenv ilThisTy m = GenPrintingMethod cenv eenv " ToString" ilThisTy m
7765+
7766+ /// Generate a ToString/get_Message method that calls 'sprintf "%A"'
7767+ and GenPrintingMethod cenv eenv methName ilThisTy m =
77147768 let g = cenv.g
77157769 [ match ( eenv.valsInScope.TryFind g.sprintf_ vref.Deref,
77167770 eenv.valsInScope.TryFind g.new_ format_ vref.Deref) with
@@ -7750,7 +7804,7 @@ and GenToStringMethod cenv eenv ilThisTy m =
77507804
77517805 let ilMethodBody = mkMethodBody ( true , [], 2 , nonBranchingInstrsToCode ilInstrs, None, eenv.imports)
77527806
7753- let mdef = mkILNonGenericVirtualMethod ( " ToString " , ILMemberAccess.Public, [], mkILReturn g.ilg.typ_ String, ilMethodBody)
7807+ let mdef = mkILNonGenericVirtualMethod ( methName , ILMemberAccess.Public, [], mkILReturn g.ilg.typ_ String, ilMethodBody)
77547808 let mdef = mdef.With( customAttrs = mkILCustomAttrs [ g.CompilerGeneratedAttribute ])
77557809 yield mdef
77567810 | _ -> () ]
@@ -8433,12 +8487,21 @@ and GenExnDef cenv mgbuf eenv m (exnc: Tycon) =
84338487
84348488 let ilTypeName = tref.Name
84358489
8490+ let ilMethodDefs =
8491+ [ ilCtorDef
8492+ yield ! ilCtorDefNoArgs
8493+ yield ! serializationRelatedMembers
8494+ yield ! ilMethodDefsForProperties
8495+
8496+ if not ( exnc.HasMember g " get_Message" []) && not ( exnc.HasMember g " Message" []) then
8497+ yield ! GenPrintingMethod cenv eenv " get_Message" ilThisTy m ]
8498+
84368499 let interfaces = exnc.ImmediateInterfaceTypesOfFSharpTycon |> List.map ( GenType cenv.amap m eenv.tyenv)
84378500 let tdef =
84388501 mkILGenericClass
84398502 ( ilTypeName, access, [], g.iltyp_ Exception,
84408503 interfaces,
8441- mkILMethods ([ ilCtorDef ] @ ilCtorDefNoArgs @ serializationRelatedMembers @ ilMethodDefsForProperties ) ,
8504+ mkILMethods ilMethodDefs ,
84428505 mkILFields ilFieldDefs,
84438506 emptyILTypeDefs,
84448507 mkILProperties ilPropertyDefs,
0 commit comments