flan/test/programs/builtin-qualified.flan
Joseph Ferano 40d62e7643 builtin/name, the spelling a shadow cannot take away
A defn named after a builtin wins for its whole file, and until now that
was the end of it: the builtin had no remaining spelling, so a defn that
meant to wrap one was unbounded recursion. builtin/len is the builtin len
wherever it is written, shadowed or not.

The qualifier is the package one's, and builtin is reserved rather than
resolved: Load refuses it as an import alias, Check refuses it as a
declaration's name, and those two doors are the only ways a qualifier can
be made. named_call and var each strip the prefix and re-enter with a flag
that the shadowing guard consults, so every arm below sees the bare name
and refuses in the builtin's own words.

The shadow warning now names the escape in its second half.
2026-09-20 20:17:17 +07:00

47 lines
2.4 KiB
Plaintext

;;;; builtin/name: the spelling that always reaches the builtin.
;;;;
;;;; Shadowing a builtin is legal and program-wide within the file that does
;;;; it (shadow-builtin.flan is that rule on its own). What it used to cost
;;;; was the builtin itself: a (defn len ...) had given up the builtin len for
;;;; the whole file, so a definition that meant to *wrap* the builtin was
;;;; unbounded recursion instead, and stack-overflowed at run time with
;;;; nothing for the compiler to object to.
;;;;
;;;; builtin/len is the way out, and it is the package qualifier's own
;;;; spelling: rl/draw-fps is draw-fps from the package imported as rl, and
;;;; builtin/len is len from the compiler. builtin is a reserved qualifier —
;;;; an import may not take it as an alias — so the two can never be confused
;;;; about which one a name means.
;;;;
;;;; Five lines, and between them the whole feature. In order:
;;;;
;;;; - 9: (builtin/max 3 9) with nothing in this program named max. The
;;;; qualifier is legal whether or not anything is shadowed; a spelling that
;;;; only compiled while some other declaration existed would be a spelling
;;;; nobody could write down in advance.
;;;; - 5: this file's own len, which is a real wrapper — it is "1 + the
;;;; builtin length", and the inner call reaches the builtin rather than
;;;; itself. This is the program the earlier lane could not write.
;;;; - 4: builtin/len in the same file, beside the bare name that means the
;;;; definition. Both spellings, one program, different answers.
;;;; - 99: the shadowed operator, unchanged. An operator is a builtin like any
;;;; other and shadows like any other.
;;;; - 3: builtin/+ — the reader takes builtin/+ as one symbol, because '/'
;;;; and '+' are both ordinary symbol characters and the token does not
;;;; begin with a digit or a sign, so an operator needs no exception here.
;;; The wrapper, written the way the dead end said could not be written: the
;;; inner builtin/len is the compiler's len, and the outer name is this one.
;;; Both additions are qualified too, since + is shadowed below and this
;;; function wants the arithmetic and not the 99.
(defn len [s string] i32 (builtin/+ 1 (builtin/len s)))
(defn + [a i32 b i32] i32 99)
(defn main [] ()
(println (builtin/max 3 9))
(println (len "abcd"))
(println (builtin/len "abcd"))
(println (+ 1 2))
(println (builtin/+ 1 2)))