1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::{
errors::StatementError,
get_indicator_value,
program::ConstrainedProgram,
value::ConstrainedValue,
GroupType,
};
use leo_asg::{Span, Type};
use snarkvm_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{boolean::Boolean, select::CondSelectGadget},
},
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn conditionally_select_result<CS: ConstraintSystem<F>>(
cs: &mut CS,
expected_return: &Type,
results: Vec<(Boolean, ConstrainedValue<F, G>)>,
span: &Span,
) -> Result<ConstrainedValue<F, G>, StatementError> {
let mut return_value = ConstrainedValue::Tuple(vec![]);
let mut ignored = vec![];
let mut found_return = false;
for (indicator, result) in results.into_iter() {
let result_type = result.to_type(span)?;
if !expected_return.is_assignable_from(&result_type) {
panic!(
"failed type resolution for function return: expected '{}', got '{}'",
expected_return.to_string(),
result_type.to_string()
);
}
if get_indicator_value(&indicator) {
if found_return {
return Err(StatementError::multiple_returns(span.to_owned()));
} else {
return_value = result;
found_return = true;
}
} else {
ignored.push((indicator, result))
}
}
for (i, (indicator, result)) in ignored.into_iter().enumerate() {
return_value = ConstrainedValue::conditionally_select(
cs.ns(|| format!("select result {} {}:{}", i, span.line, span.start)),
&indicator,
&result,
&return_value,
)
.map_err(|_| StatementError::select_fail(result.to_string(), return_value.to_string(), span.to_owned()))?;
}
Ok(return_value)
}
}