Skip to content

Commit 482c179

Browse files
committed
Const type checking / compilation
1 parent 641b4c3 commit 482c179

File tree

9 files changed

+343
-106
lines changed

9 files changed

+343
-106
lines changed

src/ast.rs

+11
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ pub enum Type {
161161
Fn(Vec<Type>, Box<Type>),
162162
/// Array type of a fixed size, containing elements of the specified type.
163163
Array(Box<Type>, usize),
164+
/// Array type of a fixed size, with the size specified by a constant.
165+
ArrayConst(Box<Type>, String),
164166
/// Tuple type containing fields of the specified types.
165167
Tuple(Vec<Type>),
166168
/// A struct or an enum, depending on the top level definitions (used only before typechecking).
@@ -197,6 +199,13 @@ impl std::fmt::Display for Type {
197199
size.fmt(f)?;
198200
f.write_str("]")
199201
}
202+
Type::ArrayConst(ty, size) => {
203+
f.write_str("[")?;
204+
ty.fmt(f)?;
205+
f.write_str("; ")?;
206+
size.fmt(f)?;
207+
f.write_str("]")
208+
}
200209
Type::Tuple(fields) => {
201210
f.write_str("(")?;
202211
let mut fields = fields.iter();
@@ -303,6 +312,8 @@ pub enum ExprEnum<T> {
303312
ArrayLiteral(Vec<Expr<T>>),
304313
/// Array "repeat expression", which specifies 1 element, to be repeated a number of times.
305314
ArrayRepeatLiteral(Box<Expr<T>>, usize),
315+
/// Array "repeat expression", with the size specified by a constant.
316+
ArrayRepeatLiteralConst(Box<Expr<T>>, String),
306317
/// Access of an array at the specified index, returning its element.
307318
ArrayAccess(Box<Expr<T>>, Box<Expr<T>>),
308319
/// Tuple literal containing the specified fields.

src/check.rs

+52-2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ pub enum TypeErrorEnum {
113113
PatternsAreNotExhaustive(Vec<PatternStack>),
114114
/// The expression cannot be matched upon.
115115
TypeDoesNotSupportPatternMatching(Type),
116+
/// The specified identifier is not a constant.
117+
ArraySizeNotConst(String),
116118
}
117119

118120
impl std::fmt::Display for TypeErrorEnum {
@@ -223,6 +225,9 @@ impl std::fmt::Display for TypeErrorEnum {
223225
TypeErrorEnum::TypeDoesNotSupportPatternMatching(ty) => {
224226
f.write_fmt(format_args!("Type {ty} does not support pattern matching"))
225227
}
228+
TypeErrorEnum::ArraySizeNotConst(identifier) => {
229+
f.write_fmt(format_args!("Array sizes must be constants, but '{identifier}' is a variable"))
230+
}
226231
}
227232
}
228233
}
@@ -252,6 +257,10 @@ impl Type {
252257
let elem = elem.as_concrete_type(types)?;
253258
Type::Array(Box::new(elem), *size)
254259
}
260+
Type::ArrayConst(elem, size) => {
261+
let elem = elem.as_concrete_type(types)?;
262+
Type::ArrayConst(Box::new(elem), size.clone())
263+
}
255264
Type::Tuple(fields) => {
256265
let mut concrete_fields = Vec::with_capacity(fields.len());
257266
for field in fields.iter() {
@@ -792,6 +801,37 @@ impl UntypedExpr {
792801
let ty = Type::Array(Box::new(value.ty.clone()), *size);
793802
(ExprEnum::ArrayRepeatLiteral(Box::new(value), *size), ty)
794803
}
804+
ExprEnum::ArrayRepeatLiteralConst(value, size) => match env.get(size) {
805+
None => match defs.consts.get(size.as_str()) {
806+
Some(&ty) if ty == &Type::Unsigned(UnsignedNumType::Usize) => {
807+
let value = value.type_check(top_level_defs, env, fns, defs)?;
808+
let ty = Type::ArrayConst(Box::new(value.ty.clone()), size.clone());
809+
(
810+
ExprEnum::ArrayRepeatLiteralConst(Box::new(value), size.clone()),
811+
ty,
812+
)
813+
}
814+
Some(&ty) => {
815+
let e = TypeErrorEnum::UnexpectedType {
816+
expected: Type::Unsigned(UnsignedNumType::Usize),
817+
actual: ty.clone(),
818+
};
819+
return Err(vec![Some(TypeError(e, meta))]);
820+
}
821+
None => {
822+
return Err(vec![Some(TypeError(
823+
TypeErrorEnum::UnknownIdentifier(size.clone()),
824+
meta,
825+
))]);
826+
}
827+
},
828+
Some(_) => {
829+
return Err(vec![Some(TypeError(
830+
TypeErrorEnum::ArraySizeNotConst(size.clone()),
831+
meta,
832+
))]);
833+
}
834+
},
795835
ExprEnum::ArrayAccess(arr, index) => {
796836
let arr = arr.type_check(top_level_defs, env, fns, defs)?;
797837
let mut index = index.type_check(top_level_defs, env, fns, defs)?;
@@ -1124,7 +1164,7 @@ impl UntypedExpr {
11241164
| Type::Tuple(_)
11251165
| Type::Struct(_)
11261166
| Type::Enum(_) => {}
1127-
Type::Fn(_, _) | Type::Array(_, _) => {
1167+
Type::Fn(_, _) | Type::Array(_, _) | Type::ArrayConst(_, _) => {
11281168
let e = TypeErrorEnum::TypeDoesNotSupportPatternMatching(ty.clone());
11291169
return Err(vec![Some(TypeError(e, meta))]);
11301170
}
@@ -1519,6 +1559,7 @@ enum Ctor {
15191559
Struct(String, Vec<(String, Type)>),
15201560
Variant(String, String, Option<Vec<Type>>),
15211561
Array(Box<Type>, usize),
1562+
ArrayConst(Box<Type>, String),
15221563
}
15231564

15241565
type PatternStack = Vec<TypedPattern>;
@@ -1587,7 +1628,7 @@ fn specialize(ctor: &Ctor, pattern: &[TypedPattern]) -> Vec<PatternStack> {
15871628
}
15881629
_ => vec![],
15891630
},
1590-
Ctor::Array(_, _) => match head_enum {
1631+
Ctor::Array(_, _) | Ctor::ArrayConst(_, _) => match head_enum {
15911632
PatternEnum::Identifier(_) => vec![tail.collect()],
15921633
_ => vec![],
15931634
},
@@ -1793,6 +1834,7 @@ fn split_ctor(patterns: &[PatternStack], q: &[TypedPattern], defs: &Defs) -> Vec
17931834
vec![Ctor::Tuple(fields.clone())]
17941835
}
17951836
Type::Array(elem_ty, size) => vec![Ctor::Array(elem_ty.clone(), *size)],
1837+
Type::ArrayConst(elem_ty, size) => vec![Ctor::ArrayConst(elem_ty.clone(), size.clone())],
17961838
Type::Fn(_, _) => {
17971839
panic!("Type {ty:?} does not support pattern matching")
17981840
}
@@ -1889,6 +1931,14 @@ fn usefulness(patterns: Vec<PatternStack>, q: PatternStack, defs: &Defs) -> Vec<
18891931
meta,
18901932
),
18911933
),
1934+
Ctor::ArrayConst(elem_ty, size) => witness.insert(
1935+
0,
1936+
Pattern::typed(
1937+
PatternEnum::Identifier("_".to_string()),
1938+
Type::ArrayConst(elem_ty.clone(), size.clone()),
1939+
meta,
1940+
),
1941+
),
18921942
}
18931943
witnesses.push(witness);
18941944
}

src/circuit.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ pub(crate) struct CircuitBuilder {
269269
gates_optimized: usize,
270270
gate_counter: usize,
271271
panic_gates: PanicResult,
272+
consts: HashMap<String, usize>,
272273
}
273274

274275
pub(crate) const USIZE_BITS: usize = 32;
@@ -393,7 +394,7 @@ impl PanicReason {
393394
}
394395

395396
impl CircuitBuilder {
396-
pub fn new(input_gates: Vec<usize>) -> Self {
397+
pub fn new(input_gates: Vec<usize>, consts: HashMap<String, usize>) -> Self {
397398
let mut gate_counter = 2; // for const true and false
398399
for input_gates_of_party in input_gates.iter() {
399400
gate_counter += input_gates_of_party;
@@ -407,9 +408,14 @@ impl CircuitBuilder {
407408
gates_optimized: 0,
408409
gate_counter,
409410
panic_gates: PanicResult::ok(),
411+
consts,
410412
}
411413
}
412414

415+
pub fn const_sizes(&self) -> &HashMap<String, usize> {
416+
&self.consts
417+
}
418+
413419
// Pruning of useless gates (gates that are not part of the output nor used by other gates):
414420
fn remove_unused_gates(&mut self, output_gates: Vec<GateIndex>) -> Vec<GateIndex> {
415421
// To find all unused gates, we start at the output gates and recursively mark all their

0 commit comments

Comments
 (0)