fix: C backend String functions, record type aliases, docs cleanup

- Add String.fromChar, chars, substring, toUpper, toLower, replace,
  startsWith, endsWith, join to C backend
- Fix record type alias unification by adding expand_type_alias and
  unify_with_env functions
- Update docs to reflect current implementation status
- Clean up outdated roadmap items and fix inconsistencies
- Add comprehensive language comparison document

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 01:06:20 -05:00
parent ba3b713f8c
commit 33b4f57faf
11 changed files with 1694 additions and 571 deletions

View File

@@ -1173,6 +1173,73 @@ impl TypeEnv {
},
);
// Add Sql effect for database access
// Connection is represented as Int (connection ID)
let row_type = Type::Record(vec![]); // Dynamic record type
env.effects.insert(
"Sql".to_string(),
EffectDef {
name: "Sql".to_string(),
type_params: Vec::new(),
operations: vec![
EffectOpDef {
name: "open".to_string(),
params: vec![("path".to_string(), Type::String)],
return_type: Type::Int, // Connection ID
},
EffectOpDef {
name: "openMemory".to_string(),
params: vec![],
return_type: Type::Int, // Connection ID
},
EffectOpDef {
name: "close".to_string(),
params: vec![("conn".to_string(), Type::Int)],
return_type: Type::Unit,
},
EffectOpDef {
name: "execute".to_string(),
params: vec![
("conn".to_string(), Type::Int),
("sql".to_string(), Type::String),
],
return_type: Type::Int, // Rows affected
},
EffectOpDef {
name: "query".to_string(),
params: vec![
("conn".to_string(), Type::Int),
("sql".to_string(), Type::String),
],
return_type: Type::List(Box::new(Type::var())), // List of records
},
EffectOpDef {
name: "queryOne".to_string(),
params: vec![
("conn".to_string(), Type::Int),
("sql".to_string(), Type::String),
],
return_type: Type::Option(Box::new(Type::var())), // Optional record
},
EffectOpDef {
name: "beginTx".to_string(),
params: vec![("conn".to_string(), Type::Int)],
return_type: Type::Unit,
},
EffectOpDef {
name: "commit".to_string(),
params: vec![("conn".to_string(), Type::Int)],
return_type: Type::Unit,
},
EffectOpDef {
name: "rollback".to_string(),
params: vec![("conn".to_string(), Type::Int)],
return_type: Type::Unit,
},
],
},
);
// Add Some and Ok, Err constructors
// Some : fn(a) -> Option<a>
let a = Type::var();
@@ -1743,6 +1810,65 @@ impl TypeEnv {
TypeScheme::poly(type_vars, typ.clone())
}
/// Expand a Named type to its underlying structural type if it's an alias
/// This is needed for unifying record type aliases with record literals
pub fn expand_type_alias(&self, ty: &Type) -> Type {
match ty {
Type::Named(name) => {
if let Some(type_def) = self.types.get(name) {
match type_def {
TypeDef::Alias(inner) => self.expand_type_alias(inner),
// For enums and records, keep the Named type
_ => ty.clone(),
}
} else {
ty.clone()
}
}
Type::Function { params, return_type, effects, properties } => {
Type::Function {
params: params.iter().map(|p| self.expand_type_alias(p)).collect(),
return_type: Box::new(self.expand_type_alias(return_type)),
effects: effects.clone(),
properties: properties.clone(),
}
}
Type::App { constructor, args } => {
Type::App {
constructor: Box::new(self.expand_type_alias(constructor)),
args: args.iter().map(|a| self.expand_type_alias(a)).collect(),
}
}
Type::Tuple(elems) => {
Type::Tuple(elems.iter().map(|e| self.expand_type_alias(e)).collect())
}
Type::Record(fields) => {
Type::Record(fields.iter().map(|(n, t)| (n.clone(), self.expand_type_alias(t))).collect())
}
Type::List(inner) => {
Type::List(Box::new(self.expand_type_alias(inner)))
}
Type::Option(inner) => {
Type::Option(Box::new(self.expand_type_alias(inner)))
}
Type::Versioned { base, version } => {
Type::Versioned {
base: Box::new(self.expand_type_alias(base)),
version: version.clone(),
}
}
// Primitives and type variables stay as-is
_ => ty.clone(),
}
}
}
/// Unify types with type alias expansion
pub fn unify_with_env(t1: &Type, t2: &Type, env: &TypeEnv) -> Result<Substitution, String> {
let expanded1 = env.expand_type_alias(t1);
let expanded2 = env.expand_type_alias(t2);
unify(&expanded1, &expanded2)
}
/// Unification of types