use super::checked; use dever::{ compiler::{build, emit}, syntax::source::Source, }; #[test] fn emission_keeps_only_called_ownership_versions() { let text = "decorate(value: Text, loud: true) (answer: Text) { answer = value + \"!\" }\ndecorate(value: Text, loud: false) (answer: Text) { answer = value + \".\" }\nmain(value: Text, loud: Bool) (answer: Text) { answer = decorate(value + \"hello\", loud) }"; let program = checked(text).unwrap(); let source = Source::new(0, "case.dever", text.into()); let main = program .functions .iter() .position(|function| function.signature.name == "main") .unwrap(); let decorate = program .functions .iter() .position(|function| function.signature.name == "decorate") .unwrap(); let generated = emit::generate(&program, &[source], &[main].into()); assert!(generated.contains(&format!("fn function{decorate}_own0("))); assert!(!generated.contains(&format!("fn function{decorate}("))); } #[test] fn final_record_fields_keep_ownership_across_calls() { let text = "type Packet { path: Text\n values: List }\nselected(path: \"/echo\", values: List) (answer: List) { answer = values }\nselected(path: other, values: List) (answer: List) { answer = [] }\nroute(packet: Packet) (answer: List) { answer = selected(packet.path, packet.values) }\nmain() (answer: List) { packet = Packet { path = \"/echo\", values = [1, 2, 3] }\n answer = route(packet) }"; let program = checked(text).unwrap(); let source = Source::new(0, "case.dever", text.into()); let index = |name| { program .functions .iter() .position(|function| function.signature.name == name) .unwrap() }; let generated = emit::generate(&program, &[source], &[index("main")].into()); let selected = index("selected"); assert!(generated.contains(&format!("fn function{selected}_own0_own1("))); assert!(!generated.contains(&format!("fn function{selected}("))); } #[test] fn emitted_types_follow_entry_variables_errors_and_nested_fields() { let text = "type Leaf { value: Channel? }\ntype Box { leaves: List }\ntype Unused { value: AsyncStream }\nmake() (value: Box) { value = Box { leaves = [] } }\nmain() () { value = make() }\nplain() (answer: Int) { answer = 42 }"; let program = checked(text).unwrap(); let source = Source::new(0, "case.dever", text.into()); for (entry, required) in [("main", true), ("plain", false)] { let index = program .functions .iter() .position(|function| function.signature.name == entry) .unwrap(); let functions = program.reachable([index]); assert_eq!( build::runtime_features(&program, &functions).contains(&"task"), required ); let generated = emit::generate(&program, std::slice::from_ref(&source), &functions); for (index, definition) in program.definitions.iter().enumerate() { let wanted = required && matches!(definition.name.as_str(), "Leaf" | "Box"); assert_eq!( generated.contains(&format!("pub struct Type{index} {{")), wanted, "{entry}: {}", definition.name ); } } } #[test] fn unused_types_are_still_validated_before_emission() { assert_eq!( checked("type Unused { values: Channel> }\nmain() () {}") .unwrap_err() .code, "C013" ); assert_eq!( checked("type Unused { next: Unused? }\nmain() () {}") .unwrap_err() .code, "C007" ); }