Skip to content

Commit d72524b

Browse files
committed
Fix #215
1 parent c292500 commit d72524b

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Regression for #215
2+
effect Emit a with
3+
emit: a -> Unit
4+
5+
iota (n: U32) = loop (i = 0) ->
6+
if i < n then
7+
emit i
8+
recur (i + 1)
9+
10+
filter stream predicate =
11+
handle stream ()
12+
| emit x ->
13+
if predicate x then
14+
emit x
15+
resume ()
16+
17+
for stream f =
18+
handle stream ()
19+
| emit x ->
20+
f x
21+
resume ()
22+
23+
iota 10
24+
with filter (fn x -> x % 2 == 0)
25+
with for print
26+
27+
// args: --check --show-types
28+
// expected stdout:
29+
// emit : forall a. (a -> Unit can Emit a)
30+
// filter : forall a b c d e. ((Unit => a can Emit d, e) - (d => Bool can Emit d, e) -> a can Emit d, e)
31+
// for : forall a b c d e f. ((Unit => a can Emit c, f) - (c => d can f) -> a can f)
32+
// iota : U32 -> Unit can Emit U32

src/types/effects.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,11 @@ impl EffectSet {
149149
}
150150

151151
pub fn try_unify_with_bindings<'c>(
152-
&self, other: &EffectSet, bindings: &mut UnificationBindings, location: Location<'c>,
152+
&self, expected: &EffectSet, bindings: &mut UnificationBindings, location: Location<'c>,
153153
cache: &mut ModuleCache<'c>,
154154
) -> Result<(), ()> {
155155
let a = self.follow_unification_bindings(bindings, cache);
156-
let b = other.follow_unification_bindings(bindings, cache);
156+
let b = expected.follow_unification_bindings(bindings, cache);
157157

158158
let mut new_effects_in_a = Vec::new();
159159
let mut new_effects_in_b = Vec::new();
@@ -185,8 +185,10 @@ impl EffectSet {
185185
check_effects(&a.effects, &b.effects, &mut new_effects_in_b);
186186
check_effects(&b.effects, &a.effects, &mut new_effects_in_a);
187187

188-
if a.extension.is_none() && !new_effects_in_a.is_empty()
189-
|| b.extension.is_none() && !new_effects_in_b.is_empty()
188+
// Allow extra effects in `a` (actual) if `b` (expected) has extra,
189+
// but not the reverse. This allows, e.g. passing a pure function
190+
// into a function expecting a function with an effect.
191+
if b.extension.is_none() && !new_effects_in_b.is_empty()
190192
{
191193
return Err(());
192194
}
@@ -208,7 +210,11 @@ impl EffectSet {
208210
}
209211
};
210212

211-
let a_extension = extend_effects(new_effects_in_a, a.extension)?;
213+
let a_extension = match a.extension {
214+
Some(extension) => extend_effects(new_effects_in_a, Some(extension))?,
215+
None => None,
216+
};
217+
212218
let b_extension = extend_effects(new_effects_in_b, b.extension)?;
213219

214220
if let (Some(a), Some(b)) = (a_extension, b_extension) {

0 commit comments

Comments
 (0)