Skip to content

Commit 0c28175

Browse files
committed
Merge BlockstreamResearch#68: Bug fixes
27a31f3 fix: Broken intra-doc link (Christian Lewe) 3c4ead4 fix: Nonempty returns require nonempty bodies (Christian Lewe) 1d9d545 test: Add example using options (Christian Lewe) 26c36d0 fix: Compile empty option using injl (Christian Lewe) f5b12ee fix: Analyze assigned expr before bound variables (Christian Lewe) Pull request description: Fixes some bugs I found while playing around with the web IDE. ACKs for top commit: apoelstra: ACK 27a31f3 Tree-SHA512: 5b2950e3dedf393e48184cd6d13a7ad4fa23b4fb43a2f892f0c0a659c2d37d8c82ad32bbda2e45a160a45e58208c215e46d85b1d075e2c7798380979df4c9b21
2 parents 6f99023 + 27a31f3 commit 0c28175

File tree

5 files changed

+78
-13
lines changed

5 files changed

+78
-13
lines changed

example_progs/option.simf

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn checked_div_32(x: u32, y: u32) -> Option<u32> {
2+
match jet_is_zero_32(y) {
3+
true => None,
4+
false => Some(jet_divide_32(x, y)),
5+
}
6+
}
7+
8+
fn main() {
9+
let res: Option<u32> = checked_div_32(10, 3);
10+
jet_verify(jet_eq_32(3, unwrap(res)));
11+
}

src/ast.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -634,11 +634,11 @@ impl AbstractSyntaxTree for Assignment {
634634
// However, the expression evaluated in the assignment does have a type,
635635
// namely the type specified in the assignment.
636636
let ty_expr = scope.resolve(&from.ty).with_span(from)?;
637+
let expression = Expression::analyze(&from.expression, &ty_expr, scope)?;
637638
let typed_variables = from.pattern.is_of_type(&ty_expr).with_span(from)?;
638639
for (identifier, ty) in typed_variables {
639640
scope.insert_variable(identifier, ty);
640641
}
641-
let expression = Expression::analyze(&from.expression, &ty_expr, scope)?;
642642

643643
Ok(Self {
644644
pattern: from.pattern.clone(),
@@ -667,10 +667,17 @@ impl AbstractSyntaxTree for Expression {
667667
.iter()
668668
.map(|s| Statement::analyze(s, &ResolvedType::unit(), scope))
669669
.collect::<Result<Arc<[Statement]>, RichError>>()?;
670-
let ast_expression = expression
671-
.as_ref()
672-
.map(|expr| Expression::analyze(expr, ty, scope).map(Arc::new))
673-
.transpose()?;
670+
let ast_expression = match expression {
671+
Some(expression) => Expression::analyze(expression, ty, scope)
672+
.map(Arc::new)
673+
.map(Some),
674+
None if ty.is_unit() => Ok(None),
675+
None => Err(Error::ExpressionTypeMismatch(
676+
ty.clone(),
677+
ResolvedType::unit(),
678+
))
679+
.with_span(from),
680+
}?;
674681
scope.pop_scope();
675682

676683
Ok(Self {

src/compile.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ impl SingleExpression {
255255
res_a.and_then(|a| res_b.and_then(|b| ProgNode::pair(&a, &b).with_span(self)))
256256
})?
257257
}
258-
SingleExpressionInner::Option(None) => ProgNode::injr(&ProgNode::unit()),
258+
SingleExpressionInner::Option(None) => ProgNode::injl(&ProgNode::unit()),
259259
SingleExpressionInner::Either(Either::Left(inner)) => {
260260
let compiled = inner.compile(scope)?;
261261
ProgNode::injl(&compiled)

src/lib.rs

+53-6
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ mod tests {
6363
#[test]
6464
fn test_progs() {
6565
for (prog_file, wit_file) in [
66-
("add.simf", "empty.wit"),
6766
("add.simf", "empty.wit"),
6867
("array.simf", "empty.wit"),
6968
("cat.simf", "empty.wit"),
@@ -72,9 +71,11 @@ mod tests {
7271
"checksigfromstackverify.wit",
7372
),
7473
("ctv.simf", "empty.wit"),
74+
("function.simf", "empty.wit"),
7575
("list.simf", "empty.wit"),
7676
("match.simf", "empty.wit"),
7777
("nesting.simf", "empty.wit"),
78+
("option.simf", "empty.wit"),
7879
("recursive-covenant.simf", "empty.wit"),
7980
("scopes.simf", "empty.wit"),
8081
("sighash_all.simf", "empty.wit"),
@@ -85,7 +86,6 @@ mod tests {
8586
("sighash_none.simf", "sighash_none.wit"),
8687
("tuple.simf", "empty.wit"),
8788
("unwrap.simf", "empty.wit"),
88-
("function.simf", "empty.wit"),
8989
] {
9090
_test_progs(prog_file, wit_file)
9191
}
@@ -107,7 +107,12 @@ mod tests {
107107
panic!("{error}")
108108
}
109109
};
110-
let redeem_prog = match satisfy(&prog_text, &witness) {
110+
111+
assert_success(&prog_text, &witness);
112+
}
113+
114+
fn assert_success(prog_text: &str, witness: &WitnessValues) {
115+
let redeem_prog = match satisfy(prog_text, witness) {
111116
Ok(x) => x,
112117
Err(error) => {
113118
panic!("{error}");
@@ -120,10 +125,52 @@ mod tests {
120125
dbg!(&redeem_prog);
121126
println!("{}", Base64Display::new(&vec, &STANDARD));
122127

123-
let mut bit_mac = BitMachine::for_program(&redeem_prog);
128+
let mut mac = BitMachine::for_program(&redeem_prog);
124129
let env = dummy_env::dummy();
125-
bit_mac
126-
.exec(&redeem_prog, &env)
130+
mac.exec(&redeem_prog, &env)
127131
.expect("Machine execution failure");
128132
}
133+
134+
fn assert_success_empty_witness(prog_text: &str) {
135+
let witness = WitnessValues::empty();
136+
assert_success(prog_text, &witness)
137+
}
138+
139+
fn assert_satisfy_error_empty_witness(prog_text: &str, expected_error: &str) {
140+
let witness = WitnessValues::empty();
141+
match satisfy(prog_text, &witness) {
142+
Ok(_) => panic!("Accepted faulty program"),
143+
Err(error) => {
144+
if !error.contains(expected_error) {
145+
panic!("Unexpected error: {error}")
146+
}
147+
}
148+
}
149+
}
150+
151+
#[test]
152+
fn redefined_variable() {
153+
let prog_text = r#"fn main() {
154+
let beefbabe: (u16, u16) = (0xbeef, 0xbabe);
155+
let beefbabe: u32 = <(u16, u16)>::into(beefbabe);
156+
}
157+
"#;
158+
assert_success_empty_witness(prog_text);
159+
}
160+
161+
#[test]
162+
fn empty_function_body_nonempty_return() {
163+
let prog_text = r#"fn my_true() -> bool {
164+
// function body is empty, although function must return `bool`
165+
}
166+
167+
fn main() {
168+
jet_verify(my_true());
169+
}
170+
"#;
171+
assert_satisfy_error_empty_witness(
172+
prog_text,
173+
"Expected expression of type `bool`, found type `()`",
174+
);
175+
}
129176
}

src/parse.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ trait PestParse: Sized {
589589
fn parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, RichError>;
590590
}
591591

592-
/// Copy of [`std::std::FromStr`] that internally uses the PEST parser.
592+
/// Copy of [`FromStr`] that internally uses the PEST parser.
593593
pub trait ParseFromStr: Sized {
594594
/// Parse a value from the string `s`.
595595
fn parse_from_str(s: &str) -> Result<Self, RichError>;

0 commit comments

Comments
 (0)