answer the module question: the partition is a path, and there is no namespacing

This commit is contained in:
bigmerge
2026-08-17 09:54:23 -05:00
3 changed files with 55 additions and 0 deletions
+6
View File
@@ -2797,6 +2797,12 @@ fn params_to_env_args(params: [Any]) -> String {
fn cg_fn(stmt: Map<String, Any>) -> Void {
let fn_name: String = stmt["name"]
state_set("__cg_current_fn", fn_name)
// Record every top-level definition. El has NO namespacing -- imports are
// textual inlining, so two modules defining the same name emit two C
// functions into one translation unit. cc catches it, but names the
// generated helpers first and the user's fn fourth. Recording it lets the
// collision be reported at El level, in El terms.
record_call(fn_name, "defines")
// Emit which constructs this fn carries, so the prohibition check can be a
// query over relations instead of a walk inside the emitter.
let cdl = stmt["decorators"]
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Control for duplicate-definition detection.
#
# El has no namespacing: import is textual inlining, so two modules defining the
# same name emit two C functions into one translation unit.
set -uo pipefail
ELC="${1:?usage: definitions_query.sh <elc>}"
LANG_DIR="${2:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
W=$(mktemp -d); trap 'rm -rf "$W"' EXIT; F=0
chk(){ [ "$2" = "$3" ] && printf ' ok %s\n' "$1" || { printf ' FAIL %s\n expected %s got %s\n' "$1" "$2" "$3"; F=$((F+1)); }; }
printf 'fn helper() -> Int { return 1 }\n' > "$W/a.el"
printf 'fn helper() -> Int { return 2 }\n' > "$W/b.el"
printf 'import "a.el"\nimport "b.el"\nfn main() { println(int_to_str(helper())) }\n' > "$W/m.el"
EL_RELATIONS_OUT="$W/r.txt" "$ELC" "$W/m.el" >/dev/null 2>&1
out=$("$LANG_DIR/tools/check/definitions.sh" "$W/r.txt" 2>&1); rc=$?
chk "a collision across modules is caught at El level" "1" "$rc"
chk "the colliding name is reported" "1" "$(echo "$out" | grep -c "'helper' is defined 2 times")"
chk "and the reason is given" "1" "$(echo "$out" | grep -c 'no namespacing')"
printf 'fn only_once() -> Int { return 1 }\nfn main() { println(int_to_str(only_once())) }\n' > "$W/c.el"
EL_RELATIONS_OUT="$W/r2.txt" "$ELC" "$W/c.el" >/dev/null 2>&1
"$LANG_DIR/tools/check/definitions.sh" "$W/r2.txt" >/dev/null 2>&1
chk "a clean program exits 0" "0" "$?"
echo; echo " 4 assertions, $((4-F)) passed, $F failed"; exit $F
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# definitions.sh — catch duplicate top-level definitions at El level.
#
# El has no namespacing. `import` is textual inlining, so two modules defining
# the same name emit two C functions into one translation unit. cc does catch
# it, but reports the generated helpers (__el_body_f, __env_f, __thunk_f) before
# the user's own function, so the first three errors name symbols the user never
# wrote.
#
# LIMIT, stated rather than hidden: textual inlining destroys file provenance.
# By the time codegen runs there is one source string and no record of which
# file a definition came from, so this can say WHICH name collides but not which
# files. Naming the files needs provenance threaded through resolve_imports.
set -uo pipefail
REL="${1:?usage: definitions.sh <relations-file>}"
[ -f "$REL" ] || exit 0
V=0
while read -r name count; do
[ "$count" -gt 1 ] || continue
printf "duplicate definition: '%s' is defined %s times — El has no namespacing, so imported modules share one global scope\n" "$name" "$count"
V=$((V+1))
done < <(grep ' calls defines$' "$REL" | awk '{print $1}' | sort | uniq -c | awk '{print $2, $1}')
[ "$V" -eq 0 ] && echo "definitions: clean"
exit "$V"