plum

#treesitter#compiler#wasm

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

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


42d88a3Peter John 2026-07-20T12:15:01+05:30
fix(plum-checker): reject a name declared as both a class and an enum variant
plum-checker/src/lib.rs CHANGED
@@ -141,6 +141,18 @@ pub fn check_source(source: &ast::Source) -> CheckResult<()> {
141
141
  let (global_env, classes, methods, enum_variants) = build_global_tables(source);
142
142
  let ctx = CheckCtx { classes: &classes, methods: &methods, enum_variants: &enum_variants };
143
143
 
144
+ // A name that is both a class and an enum variant is ambiguous: `Name(...)`
145
+ // could mean either construction, and downstream code (both the checker's
146
+ // `infer_expr` and codegen) consults `enum_variants` first, so the class
147
+ // constructor would be silently shadowed with no diagnostic. Reject it.
148
+ for name in classes.keys() {
149
+ if enum_variants.contains_key(name) {
150
+ errors.push(CheckError {
151
+ message: format!("'{}' is declared as both a class and an enum variant", name),
152
+ });
153
+ }
154
+ }
155
+
144
156
  for item in &source.items {
145
157
  if let ast::Item::Fn(f) = item {
146
158
  let mut local_errors = check_fn(f, &global_env, &ctx);
plum-checker/tests/checker_tests.rs CHANGED
@@ -291,3 +291,27 @@ bad(s: Shape) -> Float =
291
291
  let result = check_source(&source);
292
292
  assert!(result.is_err());
293
293
  }
294
+
295
+ #[test]
296
+ fn class_name_colliding_with_enum_variant_is_a_clear_error() {
297
+ // `Cat(...)` is ambiguous when `Cat` is both a class and an enum variant:
298
+ // downstream code consults `enum_variants` first, so the class
299
+ // constructor would otherwise be silently shadowed with no diagnostic.
300
+ let src = "\
301
+ type Cat =
302
+ name: Str
303
+
304
+ enum Animal =
305
+ | Cat
306
+ | Dog
307
+ ";
308
+ let source = parse(src);
309
+ let result = check_source(&source);
310
+ assert!(result.is_err(), "expected Err");
311
+ let errs = result.unwrap_err();
312
+ assert!(
313
+ errs.iter().any(|e| e.message.contains("is declared as both a class and an enum variant")),
314
+ "got: {:?}",
315
+ errs
316
+ );
317
+ }