plum

#treesitter#compiler#wasm

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

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


add63b7 — Peter John 2026-11-02T19:49:59+05:30
T4: checker trait rules
plum-checker/src/lib.rs CHANGED
@@ -3284,7 +3284,11 @@ fn checkMatch(
3284
3284
  let lowered = m.cases.iter().any(|c| {
3285
3285
  c.patterns.iter().any(|p| match p {
3286
3286
  ast::CasePattern::Class { name, .. } | ast::CasePattern::Name(name) => {
3287
- name.contains("__")
3287
+ name.starts_with(&format!("{tn}__"))
3288
+ && ctx
3289
+ .enum_variants
3290
+ .get(name.as_str())
3291
+ .is_some_and(|i| &i.enum_name == tn)
3288
3292
  }
3289
3293
  _ => false,
3290
3294
  })
plum-checker/tests/trait_fields_tests.rs CHANGED
@@ -220,3 +220,33 @@ fn typed_source_lowers_field_access() {
220
220
  let low = info.lowered.expect("lowered copy");
221
221
  assert!(hasMethod(&low, "Ent", "__get_z") && hasMethod(&low, "Ent", "__set_z"));
222
222
  }
223
+
224
+ #[test]
225
+ fn fieldless_and_memberless_traits_are_exact() {
226
+ let s = lowered("trait Bare =\n fun go(self)\ntrait Lonely(q: Float) =\n fun go(self)\n");
227
+ withCtx(&s, |ctx| {
228
+ beginPlan();
229
+ assert_eq!(
230
+ traitField(&named("Bare"), "x", 1, false, ctx),
231
+ Some(Err("trait Bare has no field x".to_string()))
232
+ );
233
+ assert_eq!(
234
+ traitField(&named("Lonely"), "q", 1, false, ctx),
235
+ Some(Err("trait Lonely has no field q".to_string()))
236
+ );
237
+ takePlan();
238
+ });
239
+ }
240
+
241
+ #[test]
242
+ fn member_fallback_never_wraps_into_a_trait() {
243
+ let s = lowered("");
244
+ withCtx(&s, |ctx| {
245
+ // Hut is a member of trait Ent; `draw` is Ent's, but Hut has its own: no fallback.
246
+ assert!(plum_checker::unions::memberFallback(&named("Hut"), "draw", ctx).is_none());
247
+ // a method only the trait defines (default) must not wrap the record into it
248
+ assert!(plum_checker::unions::memberFallback(&named("Hut"), "nope", ctx).is_none());
249
+ // plain union enums still fall back
250
+ assert!(plum_checker::unions::memberFallback(&named("Circle"), "nope", ctx).is_none());
251
+ });
252
+ }