Fix non-contiguous circuit input diagnostics - #10366
Conversation
PR SummaryLow Risk Overview
Adds Reviewed by Cursor Bugbot for commit 636760d. Bugbot is set up for automated code reviews on this repo. Configure here. |
orizi
left a comment
There was a problem hiding this comment.
@orizi made 7 comments.
Reviewable status: 0 of 4 files reviewed, 7 unresolved discussions (waiting on zakazaka95).
crates/cairo-lang-semantic/src/diagnostic.rs line 75 at r1 (raw file):
/// Reports a non-contiguous circuit input set once per concrete circuit type. pub(crate) fn report_circuit_input_indices(
no reason for this to exist as a function - write it inline at callsite.
crates/cairo-lang-semantic/src/types.rs line 966 at r1 (raw file):
} /// The first gap in a circuit's sorted input indices.
move this section to after the array violation section for a more consistent ordering.
crates/cairo-lang-semantic/src/types.rs line 984 at r1 (raw file):
ty: TypeId<'db>, ) -> Option<CircuitInputIndexViolation<'db>> { let circuit_module = core_submodule(db, SmolStrId::from(db, "circuit"));
this would require adding extern_type_id at the helper - but this still is more sensible.
Suggestion:
let circuit_module = ModuleHelper::core(db).submodule("circuit").extern_type_id("Circuit");
let circuit_extern_id = circuit_module.extern_type_id("Circuit");
let circuit_input_extern_id = circuit_module.extern_type_id("CircuitInput");crates/cairo-lang-semantic/src/types.rs line 1006 at r1 (raw file):
GenericArgumentId::Type(ty) => Some(*ty), _ => None, }));
Suggestion:
let ConcreteExternTypeLongId { extern_type_id, generic_args } = extrn.long(db);
if extern_type_id != circuit_extern_id {
stack.extend(generic_args.iter().filter_map(|arg| match arg {
GenericArgumentId::Type(ty) => Some(*ty),
_ => None,
}));
} else if let [GenericArgumentId::Type(outputs)] = generic_args[..]
&& let Some((expected, actual)) =
non_contiguous_circuit_input(db, outputs, circuit_module)
{
return Some(CircuitInputIndexViolation { circuit: ty, expected, actual });
}crates/cairo-lang-semantic/src/types.rs line 1033 at r1 (raw file):
db: &'db dyn Database, outputs: TypeId<'db>, circuit_module: ModuleId<'db>,
Suggestion:
circuit_input_extern_id: ModuleId<'db>,crates/cairo-lang-semantic/src/types.rs line 1048 at r1 (raw file):
if extern_type_id.parent_module(db) == circuit_module && extern_type_id.name(db).long(db).as_str() == "CircuitInput" {
Suggestion:
let ConcreteExternTypeLongId { extern_type_id, generic_args } = extrn.long(db);
if extern_type_id == circuit_input_extern_id {crates/cairo-lang-semantic/src/types.rs line 1054 at r1 (raw file):
{ input_indices.insert(index); }
so that we would also catch very large values if relevant.
Suggestion:
if let [GenericArgumentId::Constant(index)] = generic_args[..]
&& let Some(index) = index.to_int(db)
&& let Some(index) = index.to_usize()
{
input_indices.insert(index);
}|
Addressed all seven review points in |
orizi
left a comment
There was a problem hiding this comment.
@orizi reviewed 2 files and all commit messages, made 2 comments, and resolved 6 discussions.
Reviewable status: 2 of 5 files reviewed, 3 unresolved discussions (waiting on zakazaka95).
crates/cairo-lang-semantic/src/diagnostic.rs line 46 at r2 (raw file):
builder: DiagnosticsBuilder<'db, SemanticDiagnostic<'db>>, context_module: ModuleId<'db>, pub(crate) diagnosed_circuits: OrderedHashSet<semantic::TypeId<'db>>,
this shouldn't appear here.
if we have the same problematic type twice, we can report it twice.
Code quote:
pub(crate) diagnosed_circuits: OrderedHashSet<semantic::TypeId<'db>>,crates/cairo-lang-semantic/src/types.rs line 962 at r2 (raw file):
} else if let Some(CircuitInputIndexViolation { circuit, expected, actual }) = circuit_input_index_violation(db, ty) && diagnostics.diagnosed_circuits.insert(circuit)
this shouldn't be required.
Code quote:
diagnostics.diagnosed_circuits.insert(circuit)
orizi
left a comment
There was a problem hiding this comment.
reply to reviews on https://reviewable.io/reviews/starkware-libs/cairo/10366
@orizi made 1 comment.
Reviewable status: 2 of 5 files reviewed, 3 unresolved discussions (waiting on zakazaka95).
zakazaka95
left a comment
There was a problem hiding this comment.
Acknowledged. Addressed the latest review in f3b083d. I removed the cross-use deduplication so repeated malformed uses can each report. Focused regression 1/1 and full cairo-lang-semantic 111/111 pass, along with doctests, root formatting, strict scoped Clippy, and diff checks.
@zakazaka95 made 4 comments.
Reviewable status: 2 of 5 files reviewed, 3 unresolved discussions (waiting on orizi).
crates/cairo-lang-semantic/src/diagnostic.rs line 75 at r1 (raw file):
Previously, orizi wrote…
no reason for this to exist as a function - write it inline at callsite.
Done. Inlined at the callsite in 239afb2; the standalone helper no longer exists.
crates/cairo-lang-semantic/src/diagnostic.rs line 46 at r2 (raw file):
Previously, orizi wrote…
this shouldn't appear here.
if we have the same problematic type twice, we can report it twice.
Done. Removed in f3b083d. SemanticDiagnostics no longer keeps diagnosed_circuits state, so the same problematic type can be reported at each use.
crates/cairo-lang-semantic/src/types.rs line 962 at r2 (raw file):
Previously, orizi wrote…
this shouldn't be required.
Done. Removed in f3b083d. The diagnosed_circuits insertion guard and the now-unused carried circuit value are gone.
orizi
left a comment
There was a problem hiding this comment.
@orizi reviewed 2 files and all commit messages, made 1 comment, and resolved 3 discussions.
Reviewable status: 4 of 5 files reviewed, 1 unresolved discussion (waiting on zakazaka95).
crates/cairo-lang-semantic/src/types.rs line 1132 at r3 (raw file):
GenericArgumentId::Type(ty) => Some(*ty), _ => None, }));
Suggestion:
stack.extend(
generic_args.iter().filter_map(|arg| try_extract_matches!(arg, GenericArgumentId::Type))
);
zakazaka95
left a comment
There was a problem hiding this comment.
@zakazaka95 made 1 comment.
Reviewable status: 4 of 5 files reviewed, 1 unresolved discussion (waiting on orizi).
crates/cairo-lang-semantic/src/types.rs line 1132 at r3 (raw file):
GenericArgumentId::Type(ty) => Some(*ty), _ => None, }));
Done in 636760d. The circuit regression passes, along with strict scoped Clippy and workspace formatting.
orizi
left a comment
There was a problem hiding this comment.
@orizi reviewed 1 file and all commit messages, made 2 comments, and resolved 1 discussion.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on zakazaka95).
a discussion (no related file):
@TomerStarkware @eytan-starkware for 2nd eye.
eytan-starkware
left a comment
There was a problem hiding this comment.
@eytan-starkware+AGNT made 2 comments.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on zakazaka95).
crates/cairo-lang-semantic/src/types.rs line 1188 at r4 (raw file):
continue; } stack.extend(generic_args.iter().filter_map(|arg| match arg {
Same extraction as in circuit_input_index_violation above (already switched to the macro in r4) - use it here too for consistency.
Suggestion:
stack.extend(
generic_args.iter().filter_map(|arg| try_extract_matches!(arg, GenericArgumentId::Type)),
);crates/cairo-lang-semantic/src/types.rs line 1194 at r4 (raw file):
} TypeLongId::Tuple(types) => stack.extend(types.iter().copied()), _ => {}
A Missing type here means a diagnostic was already reported and the input set is unknown, so the contiguity result below is a cascade of that error. E.g. with a typo in one input type:
use core::circuit::{CircuitElement, CircuitInput, CircuitInputs, circuit_add};
fn main() {
let a = CircuitElement::<CircuitInput<0>> {};
let b = CircuitElement::<CircuitInpt<1>> {}; // typo
let c = CircuitElement::<CircuitInput<2>> {};
let sum = circuit_add(a, b);
let _acc = (sum, c).new_inputs();
}this PR reports, on top of the E0006: Type not found at the typo:
error[E2204]: Circuit input indices must be contiguous and start at 0. Expected index 1, found 2.
--> lib.cairo:7:16
let _acc = (sum, c).new_inputs();
^^^^^^^^^^^^^^^^^^^^^
Fixing the typo makes it disappear, and it points at the wrong place. Bail out on Missing, as type_size_info does:
Suggestion:
TypeLongId::Tuple(types) => stack.extend(types.iter().copied()),
TypeLongId::Missing(_) => return None,
_ => {}Please also add the snippet above as a case in test_data/circuit, expecting only the E0006.
Summary
core::circuit::Circuittypes while they still have a source locationType of change
Why is this change needed?
Sierra circuit specialization assumes that the input indices reachable from a circuit's outputs are exactly
0..N. A gap currently reaches an infallible specialization path and crashes the compiler instead of producing an actionable source diagnostic.What was the behavior or documentation before?
Circuits using inputs such as
{0, 2}, starting at a non-zero index, or exposing only input1as an output caused an internal compiler panic.What is the behavior or documentation after?
Semantic analysis emits
E2204at the circuit expression, identifying the expected and actual index. Reusing a contiguous input remains valid.Related issue or discussion (if any)
Closes #10138.
Additional context
Latest helper refactor (
636760d): the focused circuit regression, strict all-target/all-feature Clippy, workspace formatting and diff checks pass.Earlier implementation validation (September 3):
expr_diagnostics::circuitregression: 1 passedcargo test -p cairo-lang-semantic: 111 passedcairo-lang-semanticgit diff --check