diff --git a/src/v3/compiler/tests/fixtures/r3_class_2_function_valued_data.dag b/src/v3/compiler/tests/fixtures/r3_class_2_function_valued_data.dag index e6c7baf6839..7e84e75bdb9 100644 --- a/src/v3/compiler/tests/fixtures/r3_class_2_function_valued_data.dag +++ b/src/v3/compiler/tests/fixtures/r3_class_2_function_valued_data.dag @@ -1,5 +1,21 @@ // R3 Class 2 gap representative: function-valued data is first-class. +import std.list { List, Empty, Cons } +import v3.std.dimensions { DimensionReport, Witness } + data add_one: fn(Int) -> Int = |x| x + 1 +fn gate61_empty_int_witnesses() -> List> = Empty + +fn gate61_int_witnesses(c: Int) -> List> = + Cons { head: Inhabits(c), tail: gate61_empty_int_witnesses() } + +data report_int: fn(Int) -> DimensionReport = + |x| DimensionOk { + dimension_name: "function-valued-data", + composed: x, + witnesses: gate61_int_witnesses(x) + } + fn test_function_valued_data() -> Int = add_one(41) +fn test_function_valued_dimension_report() -> DimensionReport = report_int(42) diff --git a/src/v3/compiler/tests/integration/r3_class_2_function_valued_data_test.rs b/src/v3/compiler/tests/integration/r3_class_2_function_valued_data_test.rs index 22676a5fca5..94d6110728e 100644 --- a/src/v3/compiler/tests/integration/r3_class_2_function_valued_data_test.rs +++ b/src/v3/compiler/tests/integration/r3_class_2_function_valued_data_test.rs @@ -182,7 +182,14 @@ fn substrate_gap_function_valued_data_executes_through_evaluator() { .collect(); assert_eq!( user_defined_arrow_names, - vec!["add_one", "test_function_valued_data"], + vec![ + "add_one", + "gate61_empty_int_witnesses", + "gate61_int_witnesses", + "report_int", + "test_function_valued_data", + "test_function_valued_dimension_report", + ], "only the named data callable and named caller should carry executable Arrow bodies" ); assert!( @@ -207,6 +214,80 @@ fn substrate_gap_function_valued_data_executes_through_evaluator() { assert_eq!(value, Value::LiteralValue(literal_bits_int(42))); } +#[test] +fn substrate_gap_function_valued_data_produces_dimension_report() { + let dag = cached_compile_to_dag(SOURCE, FILE); + assert!( + dag.diagnostics().is_empty(), + "representative must compile without diagnostics: {:?}", + dag.diagnostics() + ); + + let report_int = dag + .declaration_by_name("report_int") + .expect("function-valued DimensionReport data") + .id; + let report_int_decl = dag.declaration(report_int); + assert!( + report_int_decl.value_body.is_none(), + "`report_int` must lower as executable function-valued data" + ); + assert!( + matches!( + &report_int_decl.connective, + TypeConnective::Arrow { + body: ArrowBody::UserDefined(_), + .. + } + ), + "`report_int` must carry a UserDefined Arrow body" + ); + assert!( + dag.nodes().iter().any(|node| { + matches!( + node, + Behavior::Transform(t) + if matches!(&t.target, TransformTarget::Callable(target) if *target == report_int) + ) + }), + "`report_int(42)` must lower to TransformTarget::Callable(report_int)" + ); + + let entry = bind_node_id_for_fn(&dag, "test_function_valued_dimension_report"); + let mut state = EvalStateStack::with_root_frame(EvalFrame::empty()); + let strategy = EvalStrategy::ApplicativeOrder { + input_order: InputEvaluationOrder::LeftFirst, + }; + let value = evaluate_body(&dag, entry, &mut state, strategy) + .expect("function-valued data should produce DimensionReport through evaluator"); + + let Value::VariantValue { tag, payload } = value else { + panic!("expected DimensionReport::DimensionOk VariantValue"); + }; + let variant_label = dag.declarations().iter().find_map(|decl| { + let TypeConnective::Disj { variants } = &decl.connective else { + return None; + }; + variants + .iter() + .find(|variant| variant.ty == tag) + .map(|variant| variant.label.as_str()) + }); + assert_eq!( + variant_label, + Some("DimensionOk"), + "E6-G0d must materialize the canonical DimensionOk variant constructor" + ); + let Value::RecordValue(fields) = *payload else { + panic!("DimensionOk payload must be a RecordValue"); + }; + let composed = fields + .iter() + .find(|field| field.label == "composed") + .expect("DimensionOk.composed field"); + assert_eq!(composed.value, Value::LiteralValue(literal_bits_int(42))); +} + #[test] fn function_valued_data_recursion_fails_closed() { let dag = cached_compile_any(