plum

#treesitter#compiler#wasm

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

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


30ae945Peter John 2026-07-24T11:36:01+05:30
test(plum-checker): migrate test fixtures to bracket generics syntax
plum-checker/tests/checker_tests.rs CHANGED
@@ -213,7 +213,7 @@ isNone(o: Option) -> Bool = o == None
213
213
  fn variant_construction_checks_arg_count_and_types() {
214
214
  let src = "\
215
215
  enum Option =
216
- | Some(Int)
216
+ | Some[Int]
217
217
  | None
218
218
 
219
219
  makeSome(v: Int) -> Option =
@@ -243,8 +243,8 @@ bad() -> Option =
243
243
  fn variant_construction_wrong_arg_count_is_error() {
244
244
  let src = "\
245
245
  enum Shape =
246
- | Rect(Float, Float)
246
+ | Rect[Float, Float]
247
- | Circle(Float)
247
+ | Circle[Float]
248
248
 
249
249
  bad() -> Shape =
250
250
  Rect(1.0)
@@ -258,8 +258,8 @@ bad() -> Shape =
258
258
  fn constructor_pattern_binds_fields_to_declared_types() {
259
259
  let src = "\
260
260
  enum Shape =
261
- | Rect(Float, Float)
261
+ | Rect[Float, Float]
262
- | Circle(Float)
262
+ | Circle[Float]
263
263
 
264
264
  area(s: Shape) -> Float =
265
265
  match s
@@ -277,8 +277,8 @@ area(s: Shape) -> Float =
277
277
  fn constructor_pattern_wrong_field_count_is_error() {
278
278
  let src = "\
279
279
  enum Shape =
280
- | Rect(Float, Float)
280
+ | Rect[Float, Float]
281
- | Circle(Float)
281
+ | Circle[Float]
282
282
 
283
283
  bad(s: Shape) -> Float =
284
284
  match s
@@ -319,8 +319,8 @@ enum Animal =
319
319
  #[test]
320
320
  fn generic_class_instantiated_at_two_concrete_types_type_checks() {
321
321
  let src = "\
322
- type Box(a) =
322
+ type Box[T] =
323
- value: a
323
+ value: T
324
324
 
325
325
  makeIntBox() -> Box =
326
326
  Box(value: 5)
@@ -336,7 +336,7 @@ makeStrBox() -> Box =
336
336
  #[test]
337
337
  fn generic_function_called_with_different_concrete_types_per_site_type_checks() {
338
338
  let src = "\
339
- wrap(value: a) -> Bool =
339
+ wrap(value: T) -> Bool =
340
340
  True
341
341
 
342
342
  useInt() -> Bool =
@@ -353,7 +353,7 @@ useStr() -> Bool =
353
353
  #[test]
354
354
  fn generic_function_with_two_independent_type_params_type_checks() {
355
355
  let src = "\
356
- pair(first: a, second: b) -> Bool =
356
+ pair(first: T, second: U) -> Bool =
357
357
  True
358
358
 
359
359
  use() -> Bool =
@@ -372,7 +372,7 @@ fn generic_function_with_internally_inconsistent_body_is_rejected_after_speciali
372
372
  // behavior — rewriting `wrong$Str`'s `-> Int` to `-> Str` — would make the
373
373
  // whole program type-check, masking the real `expected Int, found Str` error.
374
374
  let src = "\
375
- wrong(x: a) -> Int =
375
+ wrong(x: T) -> Int =
376
376
  \"hello\"
377
377
 
378
378
  useIt() -> Str =
@@ -392,7 +392,7 @@ fn generic_enum_single_instantiation_type_checks() {
392
392
  // matched, must resolve end-to-end via check_source.
393
393
  let src = "\
394
394
  enum Option =
395
- | Some(a)
395
+ | Some[T]
396
396
  | None
397
397
 
398
398
  get() -> Int =
@@ -435,7 +435,7 @@ fn generic_enum_multiple_instantiations_coexist_and_type_check() {
435
435
  // behavior this task adds (previously this was a documented, rejected limitation).
436
436
  let src = "\
437
437
  enum Option =
438
- | Some(a)
438
+ | Some[T]
439
439
  | None
440
440
 
441
441
  useInt() -> Int =
@@ -473,10 +473,10 @@ useStr() -> Str =
473
473
  #[test]
474
474
  fn generic_method_on_generic_class_type_checks() {
475
475
  let src = "\
476
- type Box(a) =
476
+ type Box[T] =
477
- value: a
477
+ value: T
478
478
 
479
- getValue<Box>() -> a =
479
+ getValue<Box>() -> T =
480
480
  self.value
481
481
 
482
482
  use() -> Int =
@@ -499,10 +499,10 @@ fn unbounded_recursive_generic_instantiation_is_a_clear_error() {
499
499
  // declaration, which is never itself a call site and so never reaches the
500
500
  // worklist at all) and must fail with a clear, bounded error rather than hang.
501
501
  let src = "\
502
- type Box(a) =
502
+ type Box[T] =
503
- value: a
503
+ value: T
504
504
 
505
- recurse(v: a) -> Int =
505
+ recurse(v: T) -> Int =
506
506
  b = Box(value: v)
507
507
  recurse(b)
508
508
 
@@ -525,7 +525,7 @@ fn ordinary_function_with_bare_generic_enum_param_type_checks() {
525
525
  // function taking a bare generic-enum-typed parameter.
526
526
  let src = "\
527
527
  enum Option =
528
- | Some(a)
528
+ | Some[T]
529
529
  | None
530
530
 
531
531
  unwrapOr(o: Option, default: Int) -> Int =
@@ -556,10 +556,10 @@ fn ordinary_function_with_bare_generic_class_param_type_checks() {
556
556
  // now, but the identical root cause: `Box` is dropped from the monomorphized
557
557
  // output, so a bare `Box`-typed param would otherwise reference nothing.
558
558
  let src = "\
559
- type Box(a) =
559
+ type Box[T] =
560
- value: a
560
+ value: T
561
561
 
562
- getBoxValue<Box>() -> a =
562
+ getBoxValue<Box>() -> T =
563
563
  self.value
564
564
 
565
565
  sumBox(b: Box) -> Int =
plum-checker/tests/monomorphize_tests.rs CHANGED
@@ -3,12 +3,12 @@ use plum_checker::types::PlumType;
3
3
  use plum_core::ast;
4
4
 
5
5
  #[test]
6
- fn is_generic_param_name_accepts_single_lowercase_letters_only() {
6
+ fn is_generic_param_name_accepts_single_uppercase_letters_only() {
7
- assert!(is_generic_param_name("a"));
7
+ assert!(is_generic_param_name("T"));
8
- assert!(is_generic_param_name("d"));
8
+ assert!(is_generic_param_name("W"));
9
9
  assert!(!is_generic_param_name("Int"));
10
+ assert!(!is_generic_param_name("TU"));
10
- assert!(!is_generic_param_name("ab"));
11
+ assert!(!is_generic_param_name("a"));
11
- assert!(!is_generic_param_name("A"));
12
12
  assert!(!is_generic_param_name(""));
13
13
  }
14
14
 
@@ -17,37 +17,37 @@ fn class_generic_params_reads_declared_generics_list() {
17
17
  let c = ast::Class {
18
18
  name: "Box".to_string(),
19
19
  implements: vec![],
20
- generics: vec![ast::GenericParam { name: "a".to_string(), bounds: vec![] }],
20
+ generics: vec![ast::GenericParam { name: "T".to_string(), bounds: vec![] }],
21
- fields: vec![ast::Field { name: "value".to_string(), ty: ast::Type { name: "a".to_string(), generics: vec![] } }],
21
+ fields: vec![ast::Field { name: "value".to_string(), ty: ast::Type { name: "T".to_string(), generics: vec![] } }],
22
22
  };
23
- assert_eq!(class_generic_params(&c), vec!["a".to_string()]);
23
+ assert_eq!(class_generic_params(&c), vec!["T".to_string()]);
24
24
  }
25
25
 
26
26
  #[test]
27
- fn fn_generic_params_detects_implicit_lowercase_letter_types_in_order() {
27
+ fn fn_generic_params_detects_implicit_uppercase_letter_types_in_order() {
28
28
  let f = ast::Fn {
29
29
  name: "pair".to_string(),
30
30
  type_param: None,
31
31
  params: vec![
32
- ast::Param { name: "first".to_string(), ty: ast::ParamType::Type(ast::Type { name: "a".to_string(), generics: vec![] }), default: None },
32
+ ast::Param { name: "first".to_string(), ty: ast::ParamType::Type(ast::Type { name: "T".to_string(), generics: vec![] }), default: None },
33
- ast::Param { name: "second".to_string(), ty: ast::ParamType::Type(ast::Type { name: "b".to_string(), generics: vec![] }), default: None },
33
+ ast::Param { name: "second".to_string(), ty: ast::ParamType::Type(ast::Type { name: "U".to_string(), generics: vec![] }), default: None },
34
34
  ],
35
- returns: Some(ast::ReturnType { name: "Bool".to_string(), generics: vec![] }),
35
+ returns: Some(ast::Type { name: "Bool".to_string(), generics: vec![] }),
36
36
  body: ast::FnBody::Block(ast::Block { stmts: vec![] }),
37
37
  };
38
- assert_eq!(fn_generic_params(&f), vec!["a".to_string(), "b".to_string()]);
38
+ assert_eq!(fn_generic_params(&f), vec!["T".to_string(), "U".to_string()]);
39
39
  }
40
40
 
41
41
  #[test]
42
- fn enum_generic_params_detects_implicit_lowercase_letter_variant_fields() {
42
+ fn enum_generic_params_detects_implicit_uppercase_letter_variant_fields() {
43
43
  let e = ast::Enum {
44
44
  name: "Option".to_string(),
45
45
  variants: vec![
46
- ast::EnumVariant { name: "Some".to_string(), fields: vec!["a".to_string()] },
46
+ ast::EnumVariant { name: "Some".to_string(), fields: vec!["T".to_string()] },
47
47
  ast::EnumVariant { name: "None".to_string(), fields: vec![] },
48
48
  ],
49
49
  };
50
- assert_eq!(enum_generic_params(&e), vec!["a".to_string()]);
50
+ assert_eq!(enum_generic_params(&e), vec!["T".to_string()]);
51
51
  }
52
52
 
53
53
  #[test]
@@ -62,11 +62,11 @@ fn specialize_class_substitutes_generic_field_types_and_clears_generics_list() {
62
62
  let c = ast::Class {
63
63
  name: "Box".to_string(),
64
64
  implements: vec![],
65
- generics: vec![ast::GenericParam { name: "a".to_string(), bounds: vec![] }],
65
+ generics: vec![ast::GenericParam { name: "T".to_string(), bounds: vec![] }],
66
- fields: vec![ast::Field { name: "value".to_string(), ty: ast::Type { name: "a".to_string(), generics: vec![] } }],
66
+ fields: vec![ast::Field { name: "value".to_string(), ty: ast::Type { name: "T".to_string(), generics: vec![] } }],
67
67
  };
68
68
  let mut bindings = std::collections::BTreeMap::new();
69
- bindings.insert("a".to_string(), PlumType::TInt);
69
+ bindings.insert("T".to_string(), PlumType::TInt);
70
70
  let specialized = specialize_class(&c, &Substitution(bindings), "Box$Int");
71
71
  assert_eq!(specialized.name, "Box$Int");
72
72
  assert!(specialized.generics.is_empty());
@@ -78,12 +78,12 @@ fn specialize_fn_substitutes_generic_param_and_return_types() {
78
78
  let f = ast::Fn {
79
79
  name: "wrap".to_string(),
80
80
  type_param: None,
81
- params: vec![ast::Param { name: "value".to_string(), ty: ast::ParamType::Type(ast::Type { name: "a".to_string(), generics: vec![] }), default: None }],
81
+ params: vec![ast::Param { name: "value".to_string(), ty: ast::ParamType::Type(ast::Type { name: "T".to_string(), generics: vec![] }), default: None }],
82
- returns: Some(ast::ReturnType { name: "a".to_string(), generics: vec![] }),
82
+ returns: Some(ast::Type { name: "T".to_string(), generics: vec![] }),
83
83
  body: ast::FnBody::Expr(ast::Expr::Var("value".to_string())),
84
84
  };
85
85
  let mut bindings = std::collections::BTreeMap::new();
86
- bindings.insert("a".to_string(), PlumType::TInt);
86
+ bindings.insert("T".to_string(), PlumType::TInt);
87
87
  let specialized = specialize_fn(&f, &Substitution(bindings), "wrap$Int", None);
88
88
  assert_eq!(specialized.name, "wrap$Int");
89
89
  match &specialized.params[0].ty {
@@ -99,11 +99,11 @@ fn specialize_fn_sets_new_receiver_for_a_method() {
99
99
  name: "getValue".to_string(),
100
100
  type_param: Some("Box".to_string()),
101
101
  params: vec![],
102
- returns: Some(ast::ReturnType { name: "a".to_string(), generics: vec![] }),
102
+ returns: Some(ast::Type { name: "T".to_string(), generics: vec![] }),
103
103
  body: ast::FnBody::Expr(ast::Expr::Self_),
104
104
  };
105
105
  let mut bindings = std::collections::BTreeMap::new();
106
- bindings.insert("a".to_string(), PlumType::TStr);
106
+ bindings.insert("T".to_string(), PlumType::TStr);
107
107
  let specialized = specialize_fn(&f, &Substitution(bindings), "getValue", Some("Box$Str".to_string()));
108
108
  assert_eq!(specialized.name, "getValue");
109
109
  assert_eq!(specialized.type_param, Some("Box$Str".to_string()));
@@ -115,12 +115,12 @@ fn specialize_enum_substitutes_generic_variant_field_names() {
115
115
  let e = ast::Enum {
116
116
  name: "Option".to_string(),
117
117
  variants: vec![
118
- ast::EnumVariant { name: "Some".to_string(), fields: vec!["a".to_string()] },
118
+ ast::EnumVariant { name: "Some".to_string(), fields: vec!["T".to_string()] },
119
119
  ast::EnumVariant { name: "None".to_string(), fields: vec![] },
120
120
  ],
121
121
  };
122
122
  let mut bindings = std::collections::BTreeMap::new();
123
- bindings.insert("a".to_string(), PlumType::TInt);
123
+ bindings.insert("T".to_string(), PlumType::TInt);
124
124
  let specialized = specialize_enum(&e, &Substitution(bindings), "Option$Int");
125
125
  assert_eq!(specialized.name, "Option$Int");
126
126
  assert_eq!(specialized.variants[0].fields, vec!["Int".to_string()]);