plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
69225da
— Peter John
2026-11-01T17:06:45+05:30
fix: checker errors point at the failing call, not the fn header
plum-checker/src/lib.rs
CHANGED
|
@@ -24,6 +24,9 @@ thread_local! {
|
|
|
24
24
|
/// Position (line, column) of the innermost call expression being inferred, or of the
|
|
25
25
|
/// declaration being checked outside any call: the "called at" site of recorded calls.
|
|
26
26
|
static CUR_POS: Cell<(usize, usize)> = const { Cell::new((0, 0)) };
|
|
27
|
+
/// Position of the innermost call whose inference failed, so a statement's
|
|
28
|
+
/// error points at that call rather than the enclosing fn/test header.
|
|
29
|
+
static ERR_POS: Cell<Option<(usize, usize)>> = const { Cell::new(None) };
|
|
27
30
|
/// Address of the expression `inferExprWith` is currently inferring (the innermost one).
|
|
28
31
|
static CUR_EXPR: Cell<usize> = const { Cell::new(0) };
|
|
29
32
|
/// While checking the last statement of a value-producing tail (an fn body's
|
|
@@ -2139,6 +2142,25 @@ fn checkStmt(
|
|
|
2139
2142
|
fn_name: &str,
|
|
2140
2143
|
fn_pos: (usize, usize),
|
|
2141
2144
|
ctx: &CheckCtx,
|
|
2145
|
+
) -> Vec<CheckError> {
|
|
2146
|
+
let saved = ERR_POS.with(|e| e.replace(None));
|
|
2147
|
+
let mut errors = checkStmtInner(stmt, env, declared_ret, fn_name, fn_pos, ctx);
|
|
2148
|
+
if let Some((l, c)) = ERR_POS.with(|e| e.replace(saved)) {
|
|
2149
|
+
for e in errors.iter_mut().filter(|e| (e.line, e.column) == fn_pos) {
|
|
2150
|
+
e.line = l;
|
|
2151
|
+
e.column = c;
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
errors
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
fn checkStmtInner(
|
|
2158
|
+
stmt: &ast::Stmt,
|
|
2159
|
+
env: &mut TypeEnv,
|
|
2160
|
+
declared_ret: &PlumType,
|
|
2161
|
+
fn_name: &str,
|
|
2162
|
+
fn_pos: (usize, usize),
|
|
2163
|
+
ctx: &CheckCtx,
|
|
2142
2164
|
) -> Vec<CheckError> {
|
|
2143
2165
|
let mut errors = Vec::new();
|
|
2144
2166
|
let tail = TAIL.with(|t| t.borrow_mut().take());
|
|
@@ -3475,6 +3497,9 @@ pub fn inferExprWith(
|
|
|
3475
3497
|
CUR_POS.with(|p| p.set(pos));
|
|
3476
3498
|
}
|
|
3477
3499
|
let r = inferExprInner(expr, env, ctx, expected);
|
|
3500
|
+
if r.is_err() && call_pos.is_some_and(|p| p.0 != 0) && ERR_POS.with(|e| e.get()).is_none() {
|
|
3501
|
+
ERR_POS.with(|e| e.set(call_pos));
|
|
3502
|
+
}
|
|
3478
3503
|
CUR_POS.with(|p| p.set(prev_pos));
|
|
3479
3504
|
CUR_EXPR.with(|c| c.set(prev));
|
|
3480
3505
|
if let Ok(t) = &r {
|
plum-checker/tests/checker_tests.rs
CHANGED
|
@@ -2125,5 +2125,10 @@ fn unknown_method_on_heap_const_is_checker_error() {
|
|
|
2125
2125
|
};
|
|
2126
2126
|
let msg = errText(checkSrc(&src("Cfg.CELL.size()")));
|
|
2127
2127
|
assert!(msg.contains("Box[Int] has no method 'size'"), "{}", msg);
|
|
2128
|
+
let errs = checkSrc(&src("Cfg.CELL.size()")).unwrap_err();
|
|
2129
|
+
let e = errs.iter().find(|e| e.message.contains("no method 'size'")).unwrap();
|
|
2130
|
+
assert_eq!(e.line, 13, "{:?}", e);
|
|
2131
|
+
let assign = checkSrc(&src("n := Cfg.CELL.size()\n n")).unwrap_err();
|
|
2132
|
+
assert_eq!(assign[0].line, 13, "{:?}", assign);
|
|
2128
2133
|
assert!(checkSrc(&src("Cfg.CELL.get()")).is_ok());
|
|
2129
2134
|
}
|