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:
2026-02-13 03:30:51 -05:00
parent 15e5ccb064
commit 66132779cc
6 changed files with 624 additions and 4 deletions

View File

@@ -120,6 +120,48 @@ pub struct Migration {
pub span: Span,
}
// ============ Behavioral Types ============
/// A behavioral property that can be attached to functions
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BehavioralProperty {
/// No side effects - function only depends on inputs
Pure,
/// Always terminates and doesn't throw exceptions
Total,
/// f(f(x)) == f(x) for all x
Idempotent,
/// Same inputs always produce same outputs (no randomness)
Deterministic,
/// Order of arguments doesn't matter: f(a, b) == f(b, a)
Commutative,
}
impl fmt::Display for BehavioralProperty {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BehavioralProperty::Pure => write!(f, "pure"),
BehavioralProperty::Total => write!(f, "total"),
BehavioralProperty::Idempotent => write!(f, "idempotent"),
BehavioralProperty::Deterministic => write!(f, "deterministic"),
BehavioralProperty::Commutative => write!(f, "commutative"),
}
}
}
/// A where clause constraint on a function
#[derive(Debug, Clone)]
pub enum WhereClause {
/// Type parameter has a property: where F is pure
PropertyConstraint {
type_param: Ident,
property: BehavioralProperty,
span: Span,
},
/// Result refinement: where result > 0
ResultRefinement { predicate: Box<Expr>, span: Span },
}
/// Module path: foo/bar/baz
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ModulePath {
@@ -184,6 +226,10 @@ pub struct FunctionDecl {
pub params: Vec<Parameter>,
pub return_type: TypeExpr,
pub effects: Vec<Ident>,
/// Behavioral properties: is pure, is total, etc.
pub properties: Vec<BehavioralProperty>,
/// Where clause constraints
pub where_clauses: Vec<WhereClause>,
pub body: Expr,
pub span: Span,
}