From 046d6b9757fb3a05e9d93c50ffc910f67a708747 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 18 May 2026 04:42:53 +0100 Subject: [PATCH] fix(typecheck): lenient deref so *ref-mode-param type-checks (#128) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Params declared with a ref/mut mode (e.g. `ref self`, `ref other: Int`) are lowered to their bare value type — the borrow checker tracks the actual borrow, not the type. But OpDeref required the operand to unify with `TRef tv`, so stdlib code reading ref params via `*self`/`*other` (traits.affine Eq/Ord/Hash/Display impls for Int/Bool) failed with `Unify (ref tv, Int)`. Make `*e` peel one borrow layer when e is TRef/TMut/TOwn and act as the identity on a value type. Real reference types still deref to inner; value types unchanged -> no regression. stdlib 16->17/19; 233/233 dune test, zero regression. Refs #128 Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/typecheck.ml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/typecheck.ml b/lib/typecheck.ml index 1265b018..ef9713ca 100644 --- a/lib/typecheck.ml +++ b/lib/typecheck.ml @@ -940,6 +940,18 @@ let rec synth (ctx : context) (expr : expr) : ty result = | _ -> let* () = unify_or_err operand_ty ty_int in Ok ty_int) + | OpDeref -> + (* Lenient deref: `*e` peels one borrow layer when `e` is a + reference type, but is the identity on a value type. Params + declared with a `ref`/`mut` mode are lowered to their bare + value type (the borrow checker tracks the actual borrow), so + stdlib code that reads them via `*self` / `*other` must still + type-check. Real `TRef`/`TMut`/`TOwn` still peel to the inner + type. *) + let* operand_ty = synth ctx operand in + (match repr operand_ty with + | TRef t | TMut t | TOwn t -> Ok t + | t -> Ok t) | _ -> let (operand_ty, result_ty) = type_of_unop op in let* () = check ctx operand operand_ty in