@@ -533,7 +533,6 @@ module CancellableTaskValidationCE =
533533 BackgroundCancellableTaskValidationBuilder.RunDynamic( code)
534534
535535
536- [<AutoOpen>]
537536 module CancellableTaskValidationBuilder =
538537
539538 let cancellableTaskValidation = CancellableTaskValidationBuilder()
@@ -542,7 +541,6 @@ module CancellableTaskValidationCE =
542541 BackgroundCancellableTaskValidationBuilder()
543542
544543
545- [<AutoOpen>]
546544 module LowestPriority =
547545
548546 type CancellableTaskValidationBuilderBase with
@@ -628,7 +626,6 @@ module CancellableTaskValidationCE =
628626 .GetAwaiter()
629627
630628
631- [<AutoOpen>]
632629 module LowerPriority =
633630
634631 type CancellableTaskValidationBuilderBase with
@@ -684,7 +681,6 @@ module CancellableTaskValidationCE =
684681 })
685682 .GetAwaiter()
686683
687- [<AutoOpen>]
688684 module LowerPriority2 =
689685 // Low priority extensions
690686 type CancellableTaskValidationBuilderBase with
@@ -724,7 +720,6 @@ module CancellableTaskValidationCE =
724720
725721 fun ( ct : CancellationToken ) -> Awaitable.GetAwaiter( t)
726722
727- [<AutoOpen>]
728723 module LowPriority =
729724 // Low priority extensions
730725 type CancellableTaskValidationBuilderBase with
@@ -761,7 +756,6 @@ module CancellableTaskValidationCE =
761756 )
762757 )
763758
764- [<AutoOpen>]
765759 module MediumPriority =
766760 type Microsoft.FSharp.Control.Async with
767761
@@ -816,7 +810,6 @@ module CancellableTaskValidationCE =
816810 member inline _.Source ( [<InlineIfLambda>] t : CancellableTaskResult < 'T , 'Error >) =
817811 CancellableTask.map Validation.ofResult t
818812
819- [<AutoOpen>]
820813 module HighPriority =
821814
822815 type CancellableTaskValidationBuilder with
@@ -827,16 +820,15 @@ module CancellableTaskValidationCE =
827820 member inline _.Source ( [<InlineIfLambda>] t : CancellableTaskValidation < 'T , 'Error >) =
828821 fun ct -> ( t ct) .GetAwaiter()
829822
830-
831823 member inline _.Source ( t : Task < Validation < 'T , 'Error >>) =
832824 fun ( ct : CancellationToken ) -> t.GetAwaiter()
833825
834-
835826 member inline _.Source ( t : Async < Validation < 'T , 'Error >>) =
836827 fun ct -> Async.StartAsTask( t, cancellationToken = ct) .GetAwaiter()
837828
838- [<AutoOpen>]
839829 module AsyncExtensions =
830+ open MediumPriority
831+
840832 type Microsoft.FSharp.Control.AsyncBuilder with
841833
842834 member inline this.Bind
@@ -1094,3 +1086,44 @@ module CancellableTaskValidationCE =
10941086 return Validation.zip r1 r2
10951087
10961088 }
1089+
1090+ // What's going on here?
1091+ //
1092+ // F# method overload resolution has some weird quirks we're taking advantage of to allow
1093+ // for binding (`let!/do!/return!`) many various types (Such as Task/Async/Result/Validation)
1094+ // in a computation expression. .The gist is, any member methods attached to the type itself
1095+ // (the Builder object) will be preferred above all else when selection overloads to resolve. It
1096+ // will then use the the most recent Extension Methods that have been opened. The way we structure
1097+ // these overloads is to provide the most "concrete" overloads first, and then the more generic
1098+ // ones later. For example, `Validation` is defined as a `Result<'T, 'Error list>`, but we also
1099+ // want to be able to bind to `Result` itself and create a list of errors from it. So we need to
1100+ // have a `Validation` member method in a higher module, and then a `Result` member method
1101+ // somewhere lower. Another example is `Task<Result<'T, 'Error>>` vs `Task<'T>`. We want to be able
1102+ // to bind to both, so we need to have a `Task<Result<'T, 'Error>>` member method in a higher
1103+ // module, and then a `Task<'T>` member method somewhere lower.
1104+
1105+ // NoEagerConstraintApplication also changes behavior of SRTP methods, read the
1106+ // TaskBuilder RFC for more info.
1107+
1108+ // The reason we do AutoOpens here instead of using the attribute on the module itself
1109+ // is because it may restrict how the implementation is relying on other sections, such as
1110+ // The MediumPriority module may use something from the HighPriority module. If we put the
1111+ // HighPriority module after the MediumPriority module it will fail to compile. So we don't want
1112+ // the order of the code itself to determine the priority, this allows us to control that ordering
1113+ // more explicitly.
1114+ //
1115+ // Additional readings:
1116+ // - [F# Computation Expression Method Overload Resolution Ordering](https://gist.github.com/TheAngryByrd/c8b9c8ebcda3bb162f425bfb281d2e2b)
1117+ // - [F# RFC FS-1097 - Task builder](https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0/FS-1097-task-builder.md#feature-noeagerconstraintapplicationattribute)
1118+ // - ["Most concrete" tiebreaker for generic overloads](https://github.com/fsharp/fslang-suggestions/issues/905)
1119+
1120+
1121+ [<assembly: AutoOpen( " FsToolkit.ErrorHandling.CancellableTaskValidationCE.LowestPriority" ) >]
1122+ [<assembly: AutoOpen( " FsToolkit.ErrorHandling.CancellableTaskValidationCE.LowerPriority" ) >]
1123+ [<assembly: AutoOpen( " FsToolkit.ErrorHandling.CancellableTaskValidationCE.LowerPriority2" ) >]
1124+ [<assembly: AutoOpen( " FsToolkit.ErrorHandling.CancellableTaskValidationCE.LowPriority" ) >]
1125+ [<assembly: AutoOpen( " FsToolkit.ErrorHandling.CancellableTaskValidationCE.MediumPriority" ) >]
1126+ [<assembly: AutoOpen( " FsToolkit.ErrorHandling.CancellableTaskValidationCE.HighPriority" ) >]
1127+ [<assembly: AutoOpen( " FsToolkit.ErrorHandling.CancellableTaskValidationCE.AsyncExtensions" ) >]
1128+ [<assembly: AutoOpen( " FsToolkit.ErrorHandling.CancellableTaskValidationCE.CancellableTaskValidationBuilderModule" ) >]
1129+ do ()
0 commit comments