Merge worktree-agent: add struct literals, generics, print/log builtins
This commit is contained in:
@@ -441,6 +441,41 @@ impl TypeChecker {
|
||||
Type::Map { key: Box::new(key_ty), value: Box::new(val_ty) }
|
||||
}
|
||||
}
|
||||
Expr::StructLit { type_name, fields, .. } => {
|
||||
// Look up the type definition
|
||||
match self.env.get_type(type_name).cloned() {
|
||||
Some(TypeDef::Struct { fields: declared_fields, .. }) => {
|
||||
// Check that all provided fields are valid and have compatible types
|
||||
for (field_name, field_expr) in fields {
|
||||
let got_ty = self.infer_expr(field_expr);
|
||||
if let Some((_, expected_ty)) = declared_fields.iter().find(|(n, _)| n == field_name) {
|
||||
if !self.env.check_compatible(&got_ty, expected_ty) {
|
||||
self.emit_error(TypeErrorKind::TypeMismatch {
|
||||
expected: expected_ty.to_string(),
|
||||
got: got_ty.to_string(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
self.emit_error(TypeErrorKind::UnknownField {
|
||||
type_name: type_name.clone(),
|
||||
field: field_name.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Type::Named(type_name.clone())
|
||||
}
|
||||
Some(_) => {
|
||||
self.emit_error(TypeErrorKind::UndefinedType(
|
||||
format!("{type_name} is not a struct type"),
|
||||
));
|
||||
Type::Unknown
|
||||
}
|
||||
None => {
|
||||
self.emit_error(TypeErrorKind::UndefinedType(type_name.clone()));
|
||||
Type::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ pub struct TypeEnv {
|
||||
}
|
||||
|
||||
impl TypeEnv {
|
||||
/// Create a fresh environment pre-populated with built-in types and functions.
|
||||
pub fn with_builtins() -> Self {
|
||||
let mut env = Self::default();
|
||||
env.types.insert("Int".into(), TypeDef::Primitive(Type::Int));
|
||||
@@ -105,6 +106,17 @@ impl TypeEnv {
|
||||
env.types.insert("Bool".into(), TypeDef::Primitive(Type::Bool));
|
||||
env.types.insert("Uuid".into(), TypeDef::Primitive(Type::Uuid));
|
||||
env.types.insert("Void".into(), TypeDef::Primitive(Type::Void));
|
||||
|
||||
// Register built-in output functions — accept any value (Unknown = polymorphic)
|
||||
let void_fn_any = Type::Fn {
|
||||
params: vec![Type::Unknown],
|
||||
return_type: Box::new(Type::Void),
|
||||
};
|
||||
env.functions.insert("print".into(), void_fn_any.clone());
|
||||
env.functions.insert("println".into(), void_fn_any.clone());
|
||||
env.functions.insert("log".into(), void_fn_any.clone());
|
||||
env.functions.insert("print_err".into(), void_fn_any);
|
||||
|
||||
env
|
||||
}
|
||||
|
||||
@@ -274,6 +286,11 @@ impl TypeEnv {
|
||||
let val_ty = self.resolve_type_expr(value)?;
|
||||
Ok(Type::Map { key: Box::new(key_ty), value: Box::new(val_ty) })
|
||||
}
|
||||
el_parser::TypeExpr::TypeParam(_) => {
|
||||
// Generic type parameters resolve to Unknown at the call site —
|
||||
// the actual type is inferred from arguments during call checking.
|
||||
Ok(Type::Unknown)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user