plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
0d64aff
— Peter John
2026-07-24T11:23:34+05:30
fix(plum-core): derive trait method return type from type-kind child, not the wrong 'returns' field
- plum-core/src/parser.rs +12 -1
- plum-core/tests/parser_test.rs +18 -0
plum-core/src/parser.rs
CHANGED
|
@@ -154,7 +154,18 @@ impl<'a> AstParser<'a> {
|
|
|
154
154
|
// trait_field (aliased to field): fn_identifier "(" params ")" ("->" type)?
|
|
155
155
|
let name = node.named_child(0).map(|n| self.text(n)).unwrap_or_default();
|
|
156
156
|
let params = self.collect_params_from(node);
|
|
157
|
+
|
|
158
|
+
// As with `parse_fn`'s `returns` field, the grammar's `returns` field
|
|
159
|
+
// wraps the whole `optional(seq("->", $.type))`, so
|
|
157
|
-
|
|
160
|
+
// `child_by_field_name("returns")` resolves to the anonymous "->"
|
|
161
|
+
// token, not the `type` node. Unlike `parse_fn`, a trait method has
|
|
162
|
+
// no receiver annotation, so there's at most one `type`-kind named
|
|
163
|
+
// child here, and it's unambiguously the return type when present.
|
|
164
|
+
let returns = node
|
|
165
|
+
.named_children(&mut node.walk())
|
|
166
|
+
.find(|n| n.kind() == "type")
|
|
167
|
+
.map(|n| self.parse_type(n));
|
|
168
|
+
|
|
158
169
|
TraitMethod { name, params, returns }
|
|
159
170
|
}
|
|
160
171
|
|
plum-core/tests/parser_test.rs
CHANGED
|
@@ -14,6 +14,10 @@ fn only_fn(source: &Source) -> &Fn {
|
|
|
14
14
|
source.items.iter().find_map(|i| match i { Item::Fn(f) => Some(f), _ => None }).expect("expected a Fn item")
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
fn only_trait(source: &Source) -> &Trait {
|
|
18
|
+
source.items.iter().find_map(|i| match i { Item::Trait(t) => Some(t), _ => None }).expect("expected a Trait item")
|
|
19
|
+
}
|
|
20
|
+
|
|
17
21
|
#[test]
|
|
18
22
|
fn closure_literal_parses_with_params_and_body() {
|
|
19
23
|
let src = "\
|
|
@@ -76,6 +80,20 @@ fn fn_value_type_param_parses_with_positional_types_and_return() {
|
|
|
76
80
|
assert_eq!(ret.as_ref().map(|t| t.name.clone()), Some("Bool".to_string()));
|
|
77
81
|
}
|
|
78
82
|
|
|
83
|
+
#[test]
|
|
84
|
+
fn trait_method_return_type_is_not_mangled_to_arrow_token() {
|
|
85
|
+
let src = "trait Show =\n show() -> Str\n";
|
|
86
|
+
let source = parse(src);
|
|
87
|
+
let t = only_trait(&source);
|
|
88
|
+
let method = &t.methods[0];
|
|
89
|
+
assert_eq!(method.name, "show");
|
|
90
|
+
assert_eq!(
|
|
91
|
+
method.returns.as_ref().map(|r| r.name.clone()),
|
|
92
|
+
Some("Str".to_string()),
|
|
93
|
+
"trait method return type must be the real type, not the '->' token"
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
79
97
|
#[test]
|
|
80
98
|
fn fn_value_type_param_parses_with_no_return() {
|
|
81
99
|
let src = "each(cb: fn(Int)) -> Bool =\n True\n";
|