Skip to content
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7f30ca7
Merge branch 'feat-typing' into feat-numeric-types
Soulthym Jul 29, 2025
474de8a
docs(typing): add a NOTE for BinType::infer_bin_ty_sub, for issue #432
Soulthym Jul 29, 2025
1255bc9
chores(typing): make format
Soulthym Jul 29, 2025
9f17e24
fix(typing): adapt to old parser/ast/types api
Soulthym Jul 30, 2025
926d666
feat(typing): impl Typing for Span<T: Typing>
Soulthym Jul 30, 2025
74af2b2
feat(typing): allow forwarding of idents in sty! macro
Soulthym Jul 30, 2025
5a8af93
refactor(typing): default impl for Kind for Kind::Value Types
Soulthym Jul 30, 2025
bdec887
feat(typing): impl Typing for Vec<T>
Soulthym Jul 30, 2025
cc98758
feat(typing): Aggregate Kind variant + rework Show + impl Typing for …
Soulthym Jul 31, 2025
41a3ff4
refactor(typing): rename int to uint
Soulthym Jul 31, 2025
4891f5a
feat(typing): add an optional span to the TypeError enum
Soulthym Jul 31, 2025
3ad4b90
fix(typing): properly rename Int to UInt
Soulthym Jul 31, 2025
3402d8f
feat(typing): impl Display for TypeError
Soulthym Aug 1, 2025
60fb953
refactor(typing): integrate into codebase
Soulthym Aug 1, 2025
e7fadd4
chores: cargo clippy + fmt
Soulthym Aug 1, 2025
ee8b4a7
fix(typing): fix access::Default on TraceBinding
Soulthym Aug 5, 2025
6fee06e
fix(typing): fix TraceSegment::kind()
Soulthym Aug 5, 2025
68b28ab
feat(typing): update subtyping rules: make `?` and `_` top types
Soulthym Aug 5, 2025
80e5609
fix(typing): fix trace_type macro when len == 1
Soulthym Aug 5, 2025
99d9403
Revert "fix(typing): fix access::Default on TraceBinding"
Soulthym Aug 5, 2025
72c2eba
chores(typing): make lint
Soulthym Aug 5, 2025
4f3e939
fix(mir): fix type-mismatch check on ListComprehension in translate
Soulthym Aug 6, 2025
c60f25f
feat(mir): better error reporting for translate on bin exprs + ? case
Soulthym Aug 6, 2025
636c77a
fix(parser): fix BindingType.ty() + .kind() + sema's call handling
Soulthym Aug 6, 2025
5e0cf1c
fix(typing): re-infer BinExpr bin_ty after updating its arguments
Soulthym Aug 7, 2025
a37b3d3
fix(typing): sema: report diagnostic on non-constant exponents
Soulthym Aug 7, 2025
b2c75b6
feat(typing): assert_bool primitive
Soulthym Aug 8, 2025
c8cfad3
fix(mir/translate): fix inserted enf expr
Soulthym Aug 8, 2025
9419d39
refactor(typing): rename typing crate to air_types
Soulthym Aug 26, 2025
16195e1
Merge remote-tracking branch 'upstream/next' into feat-numeric-types-…
Soulthym Sep 10, 2025
3210f36
feat(types): FunctionType::check_args_kinds
Soulthym Sep 11, 2025
1ceaadc
feat: implement typing for MIR nodes
Leo-Besancon Sep 12, 2025
46f8065
refactor: rename none::None to stale::Stale
Leo-Besancon Sep 15, 2025
f68eb25
fix: us correct op for infer_bin_ty_*
Leo-Besancon Sep 15, 2025
7efee31
refactor(types): change *_mut api + support for RefCell, Ref, and RefMut
Soulthym Sep 17, 2025
e21c2d2
refactor(types): update ast, expose Typ* traits through Link
Soulthym Sep 17, 2025
3eaf4d5
Merge branch 'feat-numeric-types-update-leo' into feat-numeric-types-…
Soulthym Sep 17, 2025
d57ae6e
feat(types): implement typing for the whole pipeline
Soulthym Sep 18, 2025
fe751bb
fix(types): fix Trace* Typing impl
Soulthym Sep 18, 2025
3c18d05
fix(types): various bug fixes
Soulthym Sep 18, 2025
49339d6
fix(types): more bug fixes, remove unused debugging
Soulthym Sep 18, 2025
7d49a85
fix(types): fix Evaluator argument types
Soulthym Sep 19, 2025
4020b8a
feat(mir): Cast primitive + translate assert_bool
Soulthym Sep 24, 2025
bd2df16
refactor(types): rename assert_bool -> as_bool
Soulthym Sep 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ members = [
"air",
"codegen/winterfell",
"codegen/ace",
"typing",
]
resolver = "2"

Expand Down
2 changes: 1 addition & 1 deletion air/src/tests/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,5 @@ fn err_ic_trace_cols_group_used_as_scalar() {
enf a[0]' = a + clk;
}";

expect_diagnostic(source, "type mismatch");
expect_diagnostic(source, "invalid binary expression");
}
3 changes: 2 additions & 1 deletion mir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ edition.workspace = true
[dependencies]
air-parser = { package = "air-parser", path = "../parser", version = "0.5" }
air-pass = { package = "air-pass", path = "../pass", version = "0.5" }
typing = { package = "typing", path = "../typing", version = "0.1" }
anyhow = { workspace = true }
derive-ir = { package = "air-derive-ir", path = "./derive-ir", version = "0.5" }
miden-core = { package = "miden-core", version = "0.13", default-features = false }
miden-diagnostics = { workspace = true }
pretty_assertions = "1.4"
rand = "0.9"
thiserror = { workspace = true }
winter-math = { package = "winter-math", version = "0.12", default-features = false }
winter-math = { package = "winter-math", version = "0.12", default-features = false }
3 changes: 3 additions & 0 deletions mir/src/ir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod owner;
mod quad_eval;
mod utils;
pub extern crate derive_ir;
pub extern crate typing;

pub use bus::Bus;
pub use derive_ir::Builder;
Expand All @@ -18,6 +19,8 @@ pub use node::Node;
pub use nodes::*;
pub use owner::Owner;
pub use quad_eval::{QuadFelt, RandomInputs};
#[allow(unused_imports)]
pub use typing::*;
pub use utils::*;
/// A trait for nodes that can have children
/// This is used with the Child trait to allow for easy traversal and manipulation of the graph
Expand Down
3 changes: 2 additions & 1 deletion mir/src/ir/nodes/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ pub use matrix::Matrix;
pub use mul::Mul;
pub use parameter::Parameter;
pub use sub::Sub;
pub use typing::*;
pub use value::{
BusAccess, ConstantValue, MirType, MirValue, PeriodicColumnAccess, PublicInputAccess,
BusAccess, ConstantValue, MirValue, PeriodicColumnAccess, PublicInputAccess,
PublicInputTableAccess, SpannedMirValue, TraceAccess, TraceAccessBinding, Value,
};
pub use vector::Vector;
8 changes: 4 additions & 4 deletions mir/src/ir/nodes/ops/parameter.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::hash::{Hash, Hasher};

use miden_diagnostics::{SourceSpan, Spanned};
use typing::*;

use super::MirType;
use crate::ir::{BackLink, Builder, Child, Link, Node, Op, Owner, Singleton};

/// A MIR operation to represent a `Parameter` in a function or evaluator.
Expand All @@ -16,19 +16,19 @@ pub struct Parameter {
/// The position of the `Parameter` in the referred node's `Parameter` list
pub position: usize,
/// The type of the `Parameter`
pub ty: MirType,
pub ty: Option<Type>,
pub _node: Singleton<Node>,
#[span]
pub span: SourceSpan,
}

impl Parameter {
pub fn create(position: usize, ty: MirType, span: SourceSpan) -> Link<Op> {
pub fn create(position: usize, ty: Type, span: SourceSpan) -> Link<Op> {
Op::Parameter(Self {
parents: Vec::default(),
ref_node: BackLink::none(),
position,
ty,
ty: Some(ty),
_node: Singleton::none(),
span,
})
Expand Down
22 changes: 1 addition & 21 deletions mir/src/ir/nodes/ops/value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use air_parser::ast::{
self, BusType, Identifier, QualifiedIdentifier, TraceColumnIndex, TraceSegmentId,
};
use air_parser::ast::{BusType, Identifier, QualifiedIdentifier, TraceColumnIndex, TraceSegmentId};
use miden_diagnostics::{SourceSpan, Spanned};

use crate::ir::{BackLink, Builder, Bus, Child, Link, Node, Op, Owner, Singleton};
Expand Down Expand Up @@ -149,24 +147,6 @@ pub struct SpannedMirValue {
pub value: MirValue,
}

#[derive(Debug, Default, Eq, PartialEq, Clone, Hash)]
pub enum MirType {
#[default]
Felt,
Vector(usize),
Matrix(usize, usize),
}

impl From<ast::Type> for MirType {
fn from(value: ast::Type) -> Self {
match value {
ast::Type::Felt => MirType::Felt,
ast::Type::Vector(n) => MirType::Vector(n),
ast::Type::Matrix(cols, rows) => MirType::Matrix(cols, rows),
}
}
}

/// Represents an access of a PeriodicColumn, similar in nature to [TraceAccess].
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct PeriodicColumnAccess {
Expand Down
16 changes: 8 additions & 8 deletions mir/src/passes/inlining.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use super::{duplicate_node_or_replace, visitor::Visitor};
use crate::{
CompileError,
ir::{
Accessor, Graph, Link, Mir, MirType, MirValue, Node, Op, Parameter, Parent, Root,
SpannedMirValue, TraceAccessBinding, Value, Vector,
Accessor, Graph, Link, Mir, MirValue, Node, Op, Parameter, Parent, Root, SpannedMirValue,
TraceAccessBinding, Type, Value, Vector,
},
};

Expand Down Expand Up @@ -515,8 +515,8 @@ fn check_evaluator_argument_sizes(
} else if let Some(parameter) = child.as_parameter() {
let Parameter { ty, .. } = parameter.deref();
let size = match ty {
MirType::Felt => 1,
MirType::Vector(len) => *len,
Some(Type::Scalar(_)) => 1,
Some(Type::Vector(_, len)) => *len,
_ => unreachable!("expected felt or vector, got {:?}", ty),
};
trace_segments_arg_vector_len += size;
Expand All @@ -535,8 +535,8 @@ fn check_evaluator_argument_sizes(
} else if let Some(parameter) = indexable.as_parameter() {
let Parameter { ty, .. } = parameter.deref();
let size = match ty {
MirType::Felt => 1,
MirType::Vector(len) => *len,
Some(Type::Scalar(_)) => 1,
Some(Type::Vector(_, len)) => *len,
_ => unreachable!("expected felt or vector, got {:?}", ty),
};
trace_segments_arg_vector_len += size;
Expand Down Expand Up @@ -637,8 +637,8 @@ fn unpack_evaluator_arguments(args: &[Link<Op>]) -> Vec<Link<Op>> {
} else if let Some(parameter) = indexable.as_parameter() {
let Parameter { ty, .. } = parameter.deref();
let _size = match ty {
MirType::Felt => 1,
MirType::Vector(len) => *len,
Some(Type::Scalar(_)) => 1,
Some(Type::Vector(_, len)) => *len,
_ => unreachable!("expected felt or vector, got {:?}", ty),
};

Expand Down
4 changes: 2 additions & 2 deletions mir/src/passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ pub fn duplicate_node(
.to_link()
.unwrap_or_else(|| panic!("invalid ref_node for parameter {parameter:?}",));
let new_param =
Parameter::create(parameter.position, parameter.ty.clone(), parameter.span());
Parameter::create(parameter.position, parameter.ty.unwrap(), parameter.span());

if let Some(_root_ref) = owner_ref.as_root() {
new_param.as_parameter_mut().unwrap().set_ref_node(owner_ref);
Expand Down Expand Up @@ -431,7 +431,7 @@ pub fn duplicate_node_or_replace(
current_replace_map.insert(node.get_ptr(), (node.clone(), new_node));
} else {
let new_param =
Parameter::create(parameter.position, parameter.ty.clone(), parameter.span());
Parameter::create(parameter.position, parameter.ty.unwrap(), parameter.span());

if let Some(_root_ref) = owner_ref.as_root() {
new_param.as_parameter_mut().unwrap().set_ref_node(owner_ref.clone());
Expand Down
79 changes: 50 additions & 29 deletions mir/src/passes/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ use std::ops::Deref;
use air_parser::{LexicalScope, ast, ast::AccessType, symbols};
use air_pass::Pass;
use miden_diagnostics::{DiagnosticsHandler, Severity, SourceSpan, Span, Spanned};
use typing::*;

use crate::{
CompileError,
ir::{
Accessor, Add, Boundary, Builder, Bus, BusAccess, BusOp, BusOpKind, Call, ConstantValue,
Enf, Evaluator, Exp, Fold, FoldOperator, For, Function, If, Link, MatchArm, Matrix, Mir,
MirType, MirValue, Mul, Op, Owner, Parameter, PublicInputAccess, PublicInputTableAccess,
Root, SpannedMirValue, Sub, TraceAccess, TraceAccessBinding, Value, Vector,
MirValue, Mul, Op, Owner, Parameter, PublicInputAccess, PublicInputTableAccess, Root,
SpannedMirValue, Sub, TraceAccess, TraceAccessBinding, Type, Value, Vector,
},
passes::duplicate_node,
};
Expand Down Expand Up @@ -189,7 +190,7 @@ impl<'a> MirBuilder<'a> {
for binding in trace_segment.bindings.iter() {
let name = binding.name.as_ref();
match &binding.ty {
ast::Type::Vector(size) => {
Type::Vector(_, size) => {
let mut params_vec = Vec::new();
let mut span = SourceSpan::UNKNOWN;
for _ in 0..*size {
Expand All @@ -203,7 +204,7 @@ impl<'a> MirBuilder<'a> {
let vector_node = Vector::create(params_vec, span);
self.bindings.insert(name.unwrap(), vector_node.clone());
},
ast::Type::Felt => {
Type::Scalar(_) => {
let param = all_params_flatten_for_trace_segment[i].clone();
i += 1;
self.bindings.insert(name.unwrap(), param.clone());
Expand Down Expand Up @@ -236,7 +237,7 @@ impl<'a> MirBuilder<'a> {
func = func.parameters(param.clone());
}
i += 1;
let ret = Parameter::create(i, self.translate_type(&ast_func.return_type), ast_func.span());
let ret = Parameter::create(i, ast_func.return_type, ast_func.span());
params.push(ret.clone());

let func = func.return_type(ret).build();
Expand Down Expand Up @@ -272,25 +273,25 @@ impl<'a> MirBuilder<'a> {
&mut self,
span: SourceSpan,
name: Option<&'a ast::Identifier>,
ty: &ast::Type,
ty: &Type,
i: &mut usize,
) -> Result<Vec<Link<Op>>, CompileError> {
match ty {
ast::Type::Felt => {
let param = Parameter::create(*i, MirType::Felt, span);
Type::Scalar(_) => {
let param = Parameter::create(*i, ty!(felt).unwrap(), span);
*i += 1;
Ok(vec![param])
},
ast::Type::Vector(size) => {
Type::Vector(_, size) => {
let mut params = Vec::new();
for _ in 0..*size {
let param = Parameter::create(*i, MirType::Felt, span);
let param = Parameter::create(*i, ty!(felt[*size]).unwrap(), span);
*i += 1;
params.push(param);
}
Ok(params)
},
ast::Type::Matrix(_rows, _cols) => {
Type::Matrix(..) => {
let span = if let Some(name) = name {
name.span()
} else {
Expand All @@ -310,21 +311,21 @@ impl<'a> MirBuilder<'a> {
&mut self,
span: SourceSpan,
name: Option<&'a ast::Identifier>,
ty: &ast::Type,
ty: &Type,
i: &mut usize,
) -> Result<Link<Op>, CompileError> {
match ty {
ast::Type::Felt => {
let param = Parameter::create(*i, MirType::Felt, span);
Type::Scalar(_) => {
let param = Parameter::create(*i, *ty, span);
*i += 1;
Ok(param)
},
ast::Type::Vector(size) => {
let param = Parameter::create(*i, MirType::Vector(*size), span);
Type::Vector(..) => {
let param = Parameter::create(*i, *ty, span);
*i += 1;
Ok(param)
},
ast::Type::Matrix(_rows, _cols) => {
Type::Matrix(..) => {
let span = if let Some(name) = name {
name.span()
} else {
Expand Down Expand Up @@ -364,14 +365,6 @@ impl<'a> MirBuilder<'a> {
Ok(func)
}

fn translate_type(&mut self, ty: &ast::Type) -> MirType {
match ty {
ast::Type::Felt => MirType::Felt,
ast::Type::Vector(size) => MirType::Vector(*size),
ast::Type::Matrix(rows, cols) => MirType::Matrix(*rows, *cols),
}
}

fn translate_statement(&mut self, stmt: &'a ast::Statement) -> Result<Link<Op>, CompileError> {
match stmt {
ast::Statement::Let(let_stmt) => self.translate_let(let_stmt),
Expand Down Expand Up @@ -451,7 +444,8 @@ impl<'a> MirBuilder<'a> {

self.bindings.enter();
for (index, binding) in list_comp.bindings.iter().enumerate() {
let binding_node = Parameter::create(index, ast::Type::Felt.into(), binding.span());
// TODO: extract the type from the bound variable
let binding_node = Parameter::create(index, ty!(felt).unwrap(), binding.span());
params.push(binding_node.clone());
self.bindings.insert(binding, binding_node);
}
Expand Down Expand Up @@ -824,6 +818,32 @@ impl<'a> MirBuilder<'a> {
.build();
Ok(node)
},
symbols::AssertBool => {
assert_eq!(call.args.len(), 1);
let x = self.translate_expr(call.args.first().unwrap())?;
// enf x^2 = x
let enforced =
Sub::builder()
.lhs(x.clone())
.rhs(
Exp::builder()
.lhs(x.clone())
.rhs(self.translate_const(
&ast::ConstantExpr::Scalar(2),
call.span(),
)?)
.span(call.span())
.build(),
)
.span(call.span())
.build();
let node = Enf::builder().span(call.span()).expr(enforced).build();
let _ = self.insert_enforce(node);
let bool_x = duplicate_node(x, &mut Default::default());
// TODO: cast to a bool
//bool_x.update_ty(ty!(bool));
Ok(bool_x)
},
other => unimplemented!("unhandled builtin: {}", other),
}
} else {
Expand Down Expand Up @@ -941,7 +961,8 @@ impl<'a> MirBuilder<'a> {
self.bindings.enter();
let mut params = Vec::new();
for (index, binding) in list_comp.bindings.iter().enumerate() {
let binding_node = Parameter::create(index, ast::Type::Felt.into(), binding.span());
// TODO: extract the type from the bound variable
let binding_node = Parameter::create(index, ty!(felt).unwrap(), binding.span());
params.push(binding_node.clone());
self.bindings.insert(binding, binding_node);
}
Expand Down Expand Up @@ -1165,8 +1186,8 @@ impl<'a> MirBuilder<'a> {
//
// In that case, replacing the default type (Felt) with the one from the access
if let Some(mut param) = let_bound_access_expr.as_parameter_mut() {
if let Some(access_ty) = &access.ty {
param.ty = self.translate_type(access_ty);
if access.ty.is_some() {
param.ty = access.ty
}
}
let accessor: Link<Op> = Accessor::create(
Expand Down
16 changes: 11 additions & 5 deletions mir/src/passes/unrolling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,9 +815,12 @@ impl UnrollingFirstPass<'_> {
AccessType::Matrix(..) => 1,
},
Op::Parameter(parameter) => match parameter.ty {
MirType::Felt => 1,
MirType::Vector(l) => l,
MirType::Matrix(l, _) => l,
Some(Type::Scalar(_)) => 1,
Some(Type::Vector(_, l)) => l,
Some(Type::Matrix(_, l, _)) => l,
_ => {
unreachable!("Parameter should have a type"); // Raise diag
},
},
_ => 1,
}
Expand Down Expand Up @@ -862,8 +865,11 @@ impl UnrollingFirstPass<'_> {
let mut new_vec = vec![];

for i in 0..iterator_expected_len {
let new_node =
Parameter::create(i, MirType::Felt, for_node.as_for().unwrap().deref().span());
let new_node = Parameter::create(
i,
ty!(felt).unwrap(),
for_node.as_for().unwrap().deref().span(),
);
new_vec.push(new_node.clone());

let iterators_i = iterators
Expand Down
Loading
Loading