plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
42d88a3
— Peter 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 +12 -0
- plum-checker/tests/checker_tests.rs +24 -0
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
|
+
}
|