@@ -7,6 +7,9 @@ import scala.util.control.NonFatal
7
7
import scala .util .NotGiven
8
8
9
9
object either :
10
+ /** This technique allows to prevent implicit search from finding the givens thanks to ambiguity. In the scope that returns `A` it will be
11
+ * impossible to find a given [[Supervised ]] and [[Forked ]].
12
+ */
10
13
private type WithoutScopeMarkers [A ] = (Supervised , Supervised ) ?=> (Forked , Forked ) ?=> A
11
14
12
15
private inline def availableInScope [A ]: Boolean =
@@ -15,18 +18,18 @@ object either:
15
18
case _ : A => true
16
19
}
17
20
18
- /** Within an [[either ]] block, allows unwrapping [[Either ]] and [[Option ]] values using [[ok() ]]. The result is the right-value of an
21
+ /** Within an [[either ]] block, allows unwrapping [[Either ]] and [[Option ]] values using [[# ok() ]]. The result is the right-value of an
19
22
* `Either`, or the defined-value of the `Option`. In case a failure is encountered (a left-value of an `Either`, or a `None`), the
20
- * computation is short-circuited and the failure becomes the result. Failures can also be reported using [[fail() ]].
23
+ * computation is short-circuited and the failure becomes the result. Failures can also be reported using [[# fail() ]].
21
24
*
22
25
* Uses the [[boundary ]]-break mechanism.
23
26
*
24
- * Uses ambiguity-based given removal technique (given't) to enable usage of [[ok() ]] combinator in [[either ]] blocks nested inside
27
+ * Uses ambiguity-based given removal technique (given't) to enable usage of [[# ok() ]] combinator in [[either ]] blocks nested inside
25
28
* [[ox.fork ]] blocks.
26
29
*
27
30
* @param body
28
- * The code block, within which [[Either ]]s and [[Option ]]s can be unwrapped using [[ok() ]]. Failures can be reported using [[ fail() ]].
29
- * Both [[ok() ]] and [[fail() ]] are extension methods.
31
+ * The code block, within which [[Either ]]s and [[Option ]]s can be unwrapped using [[# ok() ]]. Failures can be reported using
32
+ * [[ #fail() ]]. Both [[# ok() ]] and [[# fail() ]] are extension methods.
30
33
* @tparam E
31
34
* The error type.
32
35
* @tparam A
@@ -46,7 +49,7 @@ object either:
46
49
*/
47
50
inline def apply [E , A ](inline body : WithoutScopeMarkers [Label [Either [E , A ]] ?=> A ]): Either [E , A ] =
48
51
given Forked = ForkedEvidence // just to satisfy the context function
49
- given Supervised = SupervisedEvidence // just to satisfy the context function
52
+ given Supervised = SupervisedEvidence
50
53
boundary(Right (body))
51
54
52
55
extension [E , A ](inline t : Either [E , A ])
@@ -58,54 +61,54 @@ object either:
58
61
error(
59
62
" This use of .ok() belongs to either block outside of the fork and is therefore illegal. Use either block inside of the forked block."
60
63
)
61
-
62
- summonFrom {
63
- case given boundary .Label [Either [E , Nothing ]] =>
64
- t match
65
- case Left (e) => break(Left (e))
66
- case Right (a) => a
67
- case given boundary .Label [Either [Nothing , Nothing ]] =>
68
- error(" The enclosing `either` call uses a different error type.\n If it's explicitly typed, is the error type correct?" )
69
- case _ => error(" `.ok()` can only be used within an `either` call.\n Is it present?" )
70
- }
64
+ else
65
+ summonFrom {
66
+ case given boundary .Label [Either [E , Nothing ]] =>
67
+ t match
68
+ case Left (e) => break(Left (e))
69
+ case Right (a) => a
70
+ case given boundary .Label [Either [Nothing , Nothing ]] =>
71
+ error(" The enclosing `either` call uses a different error type.\n If it's explicitly typed, is the error type correct?" )
72
+ case _ => error(" `.ok()` can only be used within an `either` call.\n Is it present?" )
73
+ }
71
74
72
75
extension [A ](inline t : Option [A ])
73
76
/** Unwrap the value of the `Option`, short-circuiting the computation to the enclosing [[either ]], in case this is a `None`. Can't be
74
77
* used in forked blocks without an either block in fork to prevent escaped Breaks that crash forked threads.
75
78
*/
76
79
transparent inline def ok (): A =
77
- inline if availableInScope[Forked ] then
80
+ inline if availableInScope[Forked ] && ! availableInScope[ Supervised ] then
78
81
error(
79
82
" This use of .ok() belongs to either block outside of the fork and is therefore illegal. Use either block inside of the forked block."
80
83
)
81
-
82
- summonFrom {
83
- case given boundary .Label [Either [Unit , Nothing ]] =>
84
- t match
85
- case None => break(Left (()))
86
- case Some (a) => a
87
- case given boundary .Label [Either [Nothing , Nothing ]] =>
88
- error(
89
- " The enclosing `either` call uses a different error type.\n If it's explicitly typed, is the error type correct?\n Note that for options, the error type must contain a `Unit`."
90
- )
91
- case _ => error(" `.ok()` can only be used within an `either` call.\n Is it present?" )
92
- }
84
+ else
85
+ summonFrom {
86
+ case given boundary .Label [Either [Unit , Nothing ]] =>
87
+ t match
88
+ case None => break(Left (()))
89
+ case Some (a) => a
90
+ case given boundary .Label [Either [Nothing , Nothing ]] =>
91
+ error(
92
+ " The enclosing `either` call uses a different error type.\n If it's explicitly typed, is the error type correct?\n Note that for options, the error type must contain a `Unit`."
93
+ )
94
+ case _ => error(" `.ok()` can only be used within an `either` call.\n Is it present?" )
95
+ }
93
96
94
97
extension [E ](e : E )
95
98
/** Fail the computation by short-circuiting the enclosing [[either ]] block with en error of type `E`. Can't be used in forked blocks
96
99
* without an either block in fork to prevent escaped Breaks that crash forked threads.
97
100
*/
98
101
transparent inline def fail (): Nothing =
99
- inline if availableInScope[Forked ] then
102
+ inline if availableInScope[Forked ] && ! availableInScope[ Supervised ] then
100
103
error(
101
104
" This use of .ok() belongs to either block outside of the fork and is therefore illegal. Use either block inside of the forked block."
102
105
)
103
-
104
- summonFrom {
105
- case given boundary .Label [Either [E , Nothing ]] => break(Left (e))
106
- case given boundary .Label [Either [Nothing , Nothing ]] =>
107
- error(" The enclosing `either` call uses a different error type.\n If it's explicitly typed, is the error type correct?" )
108
- }
106
+ else
107
+ summonFrom {
108
+ case given boundary .Label [Either [E , Nothing ]] => break(Left (e))
109
+ case given boundary .Label [Either [Nothing , Nothing ]] =>
110
+ error(" The enclosing `either` call uses a different error type.\n If it's explicitly typed, is the error type correct?" )
111
+ }
109
112
110
113
/** Catches non-fatal exceptions that occur when evaluating `t` and returns them as the left side of the returned `Either`. */
111
114
inline def catching [T ](inline t : => T ): Either [Throwable , T ] =
0 commit comments