A class's name and its keyword are one dispatch value

(defmethod area point ...) and (defmethod area :point ...) were both
accepted and the second was dead code: a class stands for the keyword
its instances carry -- that is the whole of how the two dispatch styles
share a mechanism -- so the duplicate scan has to compare them as one.
It compared the written forms, which differ. Normalised in the scan and
pinned in test_flan.ml.
This commit is contained in:
Joseph Ferano 2026-09-20 15:06:36 +07:00
parent 52a1ea183a
commit 0511cc1a01
2 changed files with 17 additions and 1 deletions

View File

@ -124,9 +124,15 @@ let collect (decls : Ast.decl list) =
list: one call site reaches all of them, and it can only pass \
one number of arguments"
m.Ast.mgen want (if want = 1 then "" else "s") n;
(* A class's name and its keyword are one dispatch value — a class
stands for the keyword its instances carry, which is the whole of
how the two dispatch styles share a mechanism so [point] and
[:point] have to be compared as one or the second method is
accepted and is dead code. *)
let norm = function Ast.Dclass c -> Ast.Dkw c | k -> k in
List.iter
(fun (prev : Ast.methd) ->
if prev.Ast.mkey = m.Ast.mkey then
if norm prev.Ast.mkey = norm m.Ast.mkey then
Loc.failk "check/duplicate-method" d.Ast.dloc
"%s already has a method for %s. Two methods for one \
dispatch value is an ambiguity nothing resolves there \

View File

@ -1803,6 +1803,16 @@ let () =
(defmethod area point [p] 2)\n\
(defn main [] i32 0)"
~needle:"already has a method for point";
(* A class's name and its keyword are one value: a class stands for the
keyword its instances carry, so these two methods are the same method
written twice and the second would be dead code. *)
rejects_check "a class and its keyword are one dispatch value"
"(defclass point [x y])\n\
(defgeneric area [self] dyn)\n\
(defmethod area point [p] 1)\n\
(defmethod area :point [p] 2)\n\
(defn main [] i32 0)"
~needle:"already has a method for :point";
rejects_check "two :else methods for one generic"
"(defmulti d [x] dyn x)\n\
(defmethod d :else [x] 1)\n\