Allow backpassing with expect.
This commit is contained in:
parent
435dd0d213
commit
a57dcf3307
|
@ -1479,13 +1479,17 @@ impl AssignmentKind<bool> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssignmentKind<()> {
|
impl<T: Default> AssignmentKind<T> {
|
||||||
pub fn let_() -> Self {
|
pub fn let_() -> Self {
|
||||||
AssignmentKind::Let { backpassing: () }
|
AssignmentKind::Let {
|
||||||
|
backpassing: Default::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect() -> Self {
|
pub fn expect() -> Self {
|
||||||
AssignmentKind::Expect { backpassing: () }
|
AssignmentKind::Expect {
|
||||||
|
backpassing: Default::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1205,6 +1205,46 @@ fn backpassing_basic() {
|
||||||
assert!(check(parse(source_code)).is_ok())
|
assert!(check(parse(source_code)).is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn backpassing_expect_simple() {
|
||||||
|
let source_code = r#"
|
||||||
|
fn and_then(opt: Option<a>, then: fn(a) -> Option<b>) -> Option<b> {
|
||||||
|
when opt is {
|
||||||
|
None -> None
|
||||||
|
Some(a) -> then(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backpassing(opt_i: Option<Int>, opt_j: Option<Int>) -> Option<Int> {
|
||||||
|
expect 42 <- and_then(opt_i)
|
||||||
|
let j <- and_then(opt_j)
|
||||||
|
Some(j + 42)
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(check(parse(source_code)).is_ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn backpassing_expect_nested() {
|
||||||
|
let source_code = r#"
|
||||||
|
fn and_then(opt: Option<a>, then: fn(Option<a>) -> Option<b>) -> Option<b> {
|
||||||
|
when opt is {
|
||||||
|
None -> None
|
||||||
|
Some(a) -> then(Some(a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backpassing(opt_i: Option<Int>, opt_j: Option<Int>) -> Option<Int> {
|
||||||
|
expect Some(i) <- and_then(opt_i)
|
||||||
|
expect Some(j) <- and_then(opt_j)
|
||||||
|
Some(i + j)
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(check(parse(source_code)).is_ok())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn backpassing_interleaved_capture() {
|
fn backpassing_interleaved_capture() {
|
||||||
let source_code = r#"
|
let source_code = r#"
|
||||||
|
@ -1320,6 +1360,29 @@ fn backpassing_unsaturated_fn() {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn backpassing_expect_type_mismatch() {
|
||||||
|
let source_code = r#"
|
||||||
|
fn and_then(opt: Option<a>, then: fn(a) -> Option<b>) -> Option<b> {
|
||||||
|
when opt is {
|
||||||
|
None -> None
|
||||||
|
Some(a) -> then(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backpassing(opt_i: Option<Int>, opt_j: Option<Int>) -> Option<Int> {
|
||||||
|
expect Some(i) <- and_then(opt_i)
|
||||||
|
let j <- and_then(opt_j)
|
||||||
|
Some(i + j)
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
check(parse(source_code)),
|
||||||
|
Err((_, Error::CouldNotUnify { .. }))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn trace_if_false_ko() {
|
fn trace_if_false_ko() {
|
||||||
let source_code = r#"
|
let source_code = r#"
|
||||||
|
|
|
@ -1708,14 +1708,15 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backpass(&mut self, breakpoint: UntypedExpr, continuation: Vec<UntypedExpr>) -> UntypedExpr {
|
fn backpass(&mut self, breakpoint: UntypedExpr, continuation: Vec<UntypedExpr>) -> UntypedExpr {
|
||||||
let (assign_location, value, pattern, annotation) = match breakpoint {
|
let (value, pattern, annotation, kind, assign_location) = match breakpoint {
|
||||||
UntypedExpr::Assignment {
|
UntypedExpr::Assignment {
|
||||||
location,
|
location,
|
||||||
value,
|
value,
|
||||||
pattern,
|
pattern,
|
||||||
annotation,
|
annotation,
|
||||||
|
kind,
|
||||||
..
|
..
|
||||||
} => (location, value, pattern, annotation),
|
} => (value, pattern, annotation, kind, location),
|
||||||
_ => unreachable!("backpass misuse: breakpoint isn't an Assignment ?!"),
|
_ => unreachable!("backpass misuse: breakpoint isn't an Assignment ?!"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1723,19 +1724,23 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
// in front of the continuation sequence. This is because we do not support patterns in function argument
|
// in front of the continuation sequence. This is because we do not support patterns in function argument
|
||||||
// (which is perhaps something we should support?).
|
// (which is perhaps something we should support?).
|
||||||
let (name, continuation) = match pattern {
|
let (name, continuation) = match pattern {
|
||||||
Pattern::Var { name, .. } | Pattern::Discard { name, .. } => {
|
Pattern::Var { name, .. } | Pattern::Discard { name, .. } if kind.is_let() => {
|
||||||
(name.clone(), continuation)
|
(name.clone(), continuation)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut with_assignment = vec![UntypedExpr::Assignment {
|
let mut with_assignment = vec![UntypedExpr::Assignment {
|
||||||
location: assign_location,
|
location: assign_location,
|
||||||
value: UntypedExpr::Var {
|
value: UntypedExpr::Var {
|
||||||
location: assign_location,
|
location: value_location,
|
||||||
name: ast::BACKPASS_VARIABLE.to_string(),
|
name: ast::BACKPASS_VARIABLE.to_string(),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
pattern,
|
pattern,
|
||||||
kind: AssignmentKind::Let { backpassing: false },
|
// Erase backpassing while preserving assignment kind.
|
||||||
|
kind: match kind {
|
||||||
|
AssignmentKind::Let { .. } => AssignmentKind::let_(),
|
||||||
|
AssignmentKind::Expect { .. } => AssignmentKind::expect(),
|
||||||
|
},
|
||||||
annotation,
|
annotation,
|
||||||
}];
|
}];
|
||||||
with_assignment.extend(continuation);
|
with_assignment.extend(continuation);
|
||||||
|
@ -2126,7 +2131,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
value: Box::new(subject.clone()),
|
value: Box::new(subject.clone()),
|
||||||
pattern: clauses[0].patterns[0].clone(),
|
pattern: clauses[0].patterns[0].clone(),
|
||||||
kind: AssignmentKind::Let { backpassing: false },
|
kind: AssignmentKind::let_(),
|
||||||
annotation: None,
|
annotation: None,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue