Add behavioral types system
Implement behavioral properties for functions including: - Property annotations: is pure, is total, is idempotent, is deterministic, is commutative - Where clause constraints: where F is pure - Result refinements: where result >= 0 (parsing only, not enforced) Key changes: - AST: BehavioralProperty enum, WhereClause enum, updated FunctionDecl - Lexer: Added keywords (is, pure, total, idempotent, deterministic, commutative, where, assume) - Parser: parse_behavioral_properties(), parse_where_clauses(), parse_single_property() - Types: PropertySet for tracking function properties, updated Function type - Typechecker: Verify pure functions don't have effects, validate where clause type params Properties are informational/guarantees rather than type constraints - a pure function can be used anywhere a function is expected. Property requirements are meant to be enforced via where clauses (future work: call-site checking). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
62
src/main.rs
62
src/main.rs
@@ -788,4 +788,66 @@ c")"#;
|
||||
"#;
|
||||
assert_eq!(eval(source).unwrap(), "0");
|
||||
}
|
||||
|
||||
// ============ Behavioral Types Tests ============
|
||||
|
||||
#[test]
|
||||
fn test_behavioral_pure_function() {
|
||||
// A pure function with no effects should work
|
||||
let source = r#"
|
||||
fn double(x: Int): Int is pure = x * 2
|
||||
let result = double(21)
|
||||
"#;
|
||||
assert_eq!(eval(source).unwrap(), "42");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behavioral_total_function() {
|
||||
// A total function should work
|
||||
let source = r#"
|
||||
fn always42(): Int is total = 42
|
||||
let result = always42()
|
||||
"#;
|
||||
assert_eq!(eval(source).unwrap(), "42");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behavioral_idempotent_function() {
|
||||
// An idempotent function
|
||||
let source = r#"
|
||||
fn clamp(x: Int): Int is idempotent = if x < 0 then 0 else x
|
||||
let result = clamp(clamp(-5))
|
||||
"#;
|
||||
assert_eq!(eval(source).unwrap(), "0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behavioral_multiple_properties() {
|
||||
// A function with multiple properties
|
||||
let source = r#"
|
||||
fn identity(x: Int): Int is pure, is total = x
|
||||
let result = identity(100)
|
||||
"#;
|
||||
assert_eq!(eval(source).unwrap(), "100");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behavioral_deterministic() {
|
||||
let source = r#"
|
||||
fn square(x: Int): Int is deterministic = x * x
|
||||
let result = square(7)
|
||||
"#;
|
||||
assert_eq!(eval(source).unwrap(), "49");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behavioral_pure_with_effects_error() {
|
||||
// A pure function with effects should produce a type error
|
||||
let source = r#"
|
||||
fn bad(x: Int): Int with {Logger} is pure = x
|
||||
"#;
|
||||
let result = eval(source);
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("pure but has effects"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user