plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


d0981fbPeter John 2026-07-23T19:47:56+05:30
feat(plum-checker,plum-wasm-codegen): add PlumType::TVariadic representation
plum-checker/src/lib.rs CHANGED
@@ -114,7 +114,7 @@ pub fn build_global_tables(source: &ast::Source) -> (TypeEnv, ClassEnv, MethodEn
114
114
  let param_types: Vec<PlumType> = f.params.iter().map(|p| {
115
115
  match &p.ty {
116
116
  ast::ParamType::Type(t) => plum_type_from_ast(t),
117
- ast::ParamType::Variadic(t) => plum_type_from_ast(t),
117
+ ast::ParamType::Variadic(t) => PlumType::TVariadic(Box::new(plum_type_from_ast(t))),
118
118
  ast::ParamType::Fn(params, ret) => {
119
119
  let param_types = params.iter().map(plum_type_from_ast).collect();
120
120
  let ret_ty = ret.as_ref().map(|r| plum_type_from_ast(r)).unwrap_or(PlumType::TUnit);
@@ -184,7 +184,7 @@ fn check_fn(f: &ast::Fn, global_env: &TypeEnv, ctx: &CheckCtx) -> Vec<CheckError
184
184
  for p in &f.params {
185
185
  let ty = match &p.ty {
186
186
  ast::ParamType::Type(t) => plum_type_from_ast(t),
187
- ast::ParamType::Variadic(t) => plum_type_from_ast(t),
187
+ ast::ParamType::Variadic(t) => PlumType::TVariadic(Box::new(plum_type_from_ast(t))),
188
188
  ast::ParamType::Fn(params, ret) => {
189
189
  let param_types = params.iter().map(plum_type_from_ast).collect();
190
190
  let ret_ty = ret.as_ref().map(|r| plum_type_from_ast(r)).unwrap_or(PlumType::TUnit);
plum-checker/src/monomorphize.rs CHANGED
@@ -82,7 +82,7 @@ fn plum_type_to_ast_type(t: &PlumType) -> ast::Type {
82
82
  PlumType::TStr => "Str".to_string(),
83
83
  PlumType::TUnit => "Unit".to_string(),
84
84
  PlumType::TNamed(n) => n.clone(),
85
- PlumType::TVar(_) | PlumType::TFun(_, _) => t.to_string(),
85
+ PlumType::TVar(_) | PlumType::TFun(_, _) | PlumType::TVariadic(_) => t.to_string(),
86
86
  };
87
87
  ast::Type { name, generics: vec![] }
88
88
  }
@@ -250,7 +250,7 @@ impl<'a> Monomorphizer<'a> {
250
250
  for p in &f.params {
251
251
  let ty = match &p.ty {
252
252
  ast::ParamType::Type(t) => crate::plum_type_from_ast(t),
253
- ast::ParamType::Variadic(t) => crate::plum_type_from_ast(t),
253
+ ast::ParamType::Variadic(t) => PlumType::TVariadic(Box::new(crate::plum_type_from_ast(t))),
254
254
  ast::ParamType::Fn(params, ret) => {
255
255
  let param_types = params.iter().map(crate::plum_type_from_ast).collect();
256
256
  let ret_ty = ret.as_ref().map(|r| crate::plum_type_from_ast(r)).unwrap_or(PlumType::TUnit);
@@ -834,7 +834,7 @@ pub fn monomorphize_source(source: &ast::Source) -> Result<ast::Source, String>
834
834
  // dispatches to it can resolve its concrete return type.
835
835
  let param_types: Vec<PlumType> = specialized_method.params.iter().map(|p| match &p.ty {
836
836
  ast::ParamType::Type(t) => crate::plum_type_from_ast(t),
837
- ast::ParamType::Variadic(t) => crate::plum_type_from_ast(t),
837
+ ast::ParamType::Variadic(t) => PlumType::TVariadic(Box::new(crate::plum_type_from_ast(t))),
838
838
  ast::ParamType::Fn(params, ret) => {
839
839
  let param_types = params.iter().map(crate::plum_type_from_ast).collect();
840
840
  let ret_ty = ret.as_ref().map(|r| crate::plum_type_from_ast(r)).unwrap_or(PlumType::TUnit);
@@ -857,7 +857,7 @@ pub fn monomorphize_source(source: &ast::Source) -> Result<ast::Source, String>
857
857
  // can resolve calls to it during inference.
858
858
  let param_types: Vec<PlumType> = specialized_fn.params.iter().map(|p| match &p.ty {
859
859
  ast::ParamType::Type(t) => crate::plum_type_from_ast(t),
860
- ast::ParamType::Variadic(t) => crate::plum_type_from_ast(t),
860
+ ast::ParamType::Variadic(t) => PlumType::TVariadic(Box::new(crate::plum_type_from_ast(t))),
861
861
  ast::ParamType::Fn(params, ret) => {
862
862
  let param_types = params.iter().map(crate::plum_type_from_ast).collect();
863
863
  let ret_ty = ret.as_ref().map(|r| crate::plum_type_from_ast(r)).unwrap_or(PlumType::TUnit);
plum-checker/src/types.rs CHANGED
@@ -10,6 +10,13 @@ pub enum PlumType {
10
10
  TVar(String),
11
11
  TFun(Vec<PlumType>, Box<PlumType>),
12
12
  TNamed(String),
13
+ /// The type of a variadic parameter, e.g. `...Int` -> `TVariadic(TInt)`.
14
+ /// Appears in exactly two places: as the trailing entry of a `TFun`'s
15
+ /// param-types list (call-site arity/type checking), and as the type bound
16
+ /// to the param's name inside the function body. Its only legal use inside
17
+ /// a body is as a `for` loop's iterable — no other `unify`/`infer_expr` arm
18
+ /// handles it, so any other use is a type error by construction.
19
+ TVariadic(Box<PlumType>),
13
20
  }
14
21
 
15
22
  impl std::fmt::Display for PlumType {
@@ -26,6 +33,7 @@ impl std::fmt::Display for PlumType {
26
33
  write!(f, "({}) -> {}", ps_str.join(", "), r)
27
34
  }
28
35
  PlumType::TNamed(n) => write!(f, "{}", n),
36
+ PlumType::TVariadic(inner) => write!(f, "...{}", inner),
29
37
  }
30
38
  }
31
39
  }
plum-wasm-codegen/src/lib.rs CHANGED
@@ -360,7 +360,7 @@ fn plum_type_to_valtype(t: &PlumType) -> ValType {
360
360
  // A closure value is a single i32 pointer to its heap-allocated
361
361
  // `{table_index, env_pointer}` pair, so `TFun` is an i32 like every other
362
362
  // heap reference (`TBool`/`TStr`/`TNamed`).
363
- PlumType::TBool | PlumType::TStr | PlumType::TNamed(_) | PlumType::TFun(_, _) => ValType::I32,
363
+ PlumType::TBool | PlumType::TStr | PlumType::TNamed(_) | PlumType::TFun(_, _) | PlumType::TVariadic(_) => ValType::I32,
364
364
  PlumType::TVar(_) | PlumType::TUnit => ValType::I64,
365
365
  }
366
366
  }
@@ -886,7 +886,7 @@ fn register_int_to_string_helper(module: &mut WasmModule, bump_global: u32) -> u
886
886
  fn param_plum_type(pt: &ast::ParamType) -> PlumType {
887
887
  match pt {
888
888
  ast::ParamType::Type(t) => plum_checker::plum_type_from_ast(t),
889
- ast::ParamType::Variadic(t) => plum_checker::plum_type_from_ast(t),
889
+ ast::ParamType::Variadic(t) => PlumType::TVariadic(Box::new(plum_checker::plum_type_from_ast(t))),
890
890
  ast::ParamType::Fn(params, ret) => {
891
891
  let param_types = params.iter().map(plum_checker::plum_type_from_ast).collect();
892
892
  let ret_ty = ret.as_ref().map(|r| plum_checker::plum_type_from_ast(r)).unwrap_or(PlumType::TUnit);
@@ -1746,7 +1746,7 @@ fn compile_fn_body(f: &ast::Fn, ctx: &CompileCtx, state: &mut ModuleState) -> Re
1746
1746
  for p in &f.params {
1747
1747
  let ty = match &p.ty {
1748
1748
  ast::ParamType::Type(t) => plum_checker::plum_type_from_ast(t),
1749
- ast::ParamType::Variadic(t) => plum_checker::plum_type_from_ast(t),
1749
+ ast::ParamType::Variadic(t) => PlumType::TVariadic(Box::new(plum_checker::plum_type_from_ast(t))),
1750
1750
  ast::ParamType::Fn(params, ret) => {
1751
1751
  let param_types = params.iter().map(plum_checker::plum_type_from_ast).collect();
1752
1752
  let ret_ty = ret.as_ref().map(|r| plum_checker::plum_type_from_ast(r)).unwrap_or(PlumType::TUnit);