Skip to content

Commit bdcebf1

Browse files
committed
feat: Add is_none
There was no way to assert that an option value is None, so I add is_none which returns true if the value is None. Rust seems to have decided against unwrap_none, so I will not go down that path. rust-lang/rust#62633 assert!(is_none(x)) might produce slightly larger Simplicity expressions than a hypothetical unwrap_none(x), but I will not try to prematurely optimize any Simplicity code here. A future version of the Simfony compiler might detect assert! + is_none and produce an optimized Simplicity expression accordingly.
1 parent 56521d8 commit bdcebf1

File tree

5 files changed

+44
-1
lines changed

5 files changed

+44
-1
lines changed

src/ast.rs

+21
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ pub enum CallName {
233233
UnwrapLeft(ResolvedType),
234234
/// [`Either::unwrap_right`].
235235
UnwrapRight(ResolvedType),
236+
/// [`Option::is_none`].
237+
IsNone(ResolvedType),
236238
/// [`Option::unwrap`].
237239
Unwrap,
238240
/// [`assert`].
@@ -900,6 +902,22 @@ impl AbstractSyntaxTree for Call {
900902
scope,
901903
)?])
902904
}
905+
CallName::IsNone(some_ty) => {
906+
if from.args.len() != 1 {
907+
return Err(Error::InvalidNumberOfArguments(1, from.args.len()))
908+
.with_span(from);
909+
}
910+
let out_ty = ResolvedType::boolean();
911+
if ty != &out_ty {
912+
return Err(Error::ExpressionTypeMismatch(ty.clone(), out_ty)).with_span(from);
913+
}
914+
let arg_ty = ResolvedType::option(some_ty);
915+
Arc::from([Expression::analyze(
916+
from.args.first().unwrap(),
917+
&arg_ty,
918+
scope,
919+
)?])
920+
}
903921
CallName::Unwrap => {
904922
let args_ty = ResolvedType::option(ty.clone());
905923
if from.args.len() != 1 {
@@ -998,6 +1016,9 @@ impl AbstractSyntaxTree for CallName {
9981016
.resolve(left_ty)
9991017
.map(Self::UnwrapRight)
10001018
.with_span(from),
1019+
parse::CallName::IsNone(some_ty) => {
1020+
scope.resolve(some_ty).map(Self::IsNone).with_span(from)
1021+
}
10011022
parse::CallName::Unwrap => Ok(Self::Unwrap),
10021023
parse::CallName::Assert => Ok(Self::Assert),
10031024
parse::CallName::TypeCast(target) => {

src/compile.rs

+5
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ impl Call {
302302
let get_inner = ProgNode::assertr_take(fail_cmr, &ProgNode::iden());
303303
ProgNode::comp(&right_and_unit, &get_inner).with_span(self)
304304
}
305+
CallName::IsNone(..) => {
306+
let sum_and_unit = ProgNode::pair_unit(&args);
307+
let is_right = ProgNode::case_true_false();
308+
ProgNode::comp(&sum_and_unit, &is_right).with_span(self)
309+
}
305310
CallName::Assert => {
306311
let jet = ProgNode::jet(Elements::Verify);
307312
ProgNode::comp(&args, &jet).with_span(self)

src/minimal.pest

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ false_expr = @{ "false" }
5656
true_expr = @{ "true" }
5757
unwrap_left = { "unwrap_left::<" ~ ty ~ ">" }
5858
unwrap_right = { "unwrap_right::<" ~ ty ~ ">" }
59+
is_none = { "is_none::<" ~ ty ~ ">" }
5960
unwrap = @{ "unwrap" }
6061
assert = @{ "assert!" }
6162
type_cast = { "<" ~ ty ~ ">::into" }
62-
call_name = { jet | unwrap_left | unwrap_right | unwrap | assert | type_cast | function_name }
63+
call_name = { jet | unwrap_left | unwrap_right | is_none | unwrap | assert | type_cast | function_name }
6364
call_args = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
6465
call_expr = { call_name ~ call_args }
6566
unsigned_decimal = @{ (ASCII_DIGIT | "_")+ }

src/named.rs

+10
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,16 @@ pub trait CoreExt: CoreConstructible + Sized {
287287
fn assertr_drop(cmr: Cmr, right: &Self) -> Self {
288288
Self::assertr(cmr, &Self::drop_(right)).unwrap()
289289
}
290+
291+
/// `case false true` always type-checks.
292+
fn case_false_true() -> Self {
293+
Self::case(&Self::bit_false(), &Self::bit_true()).unwrap()
294+
}
295+
296+
/// `case true false` always type-checks.
297+
fn case_true_false() -> Self {
298+
Self::case(&Self::bit_true(), &Self::bit_false()).unwrap()
299+
}
290300
}
291301

292302
impl<N: CoreConstructible> CoreExt for N {}

src/parse.rs

+6
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ pub enum CallName {
278278
UnwrapRight(AliasedType),
279279
/// [`Option::unwrap`].
280280
Unwrap,
281+
/// [`Option::is_none`].
282+
IsNone(AliasedType),
281283
/// [`assert`].
282284
Assert,
283285
/// Cast from the given source type.
@@ -816,6 +818,10 @@ impl PestParse for CallName {
816818
let inner = pair.into_inner().next().unwrap();
817819
AliasedType::parse(inner).map(Self::UnwrapRight)
818820
}
821+
Rule::is_none => {
822+
let inner = pair.into_inner().next().unwrap();
823+
AliasedType::parse(inner).map(Self::IsNone)
824+
}
819825
Rule::unwrap => Ok(Self::Unwrap),
820826
Rule::assert => Ok(Self::Assert),
821827
Rule::type_cast => {

0 commit comments

Comments
 (0)