Per SPEC.md Imports step 2, an import that resolves to the main sequence is skipped, so the "an imported sequence may contain only function definitions and imports" check never runs on it — but BindImports still associates the name with that sequence's definitions. The main sequence is the only one allowed to declare top-level variables, so a qualified name can now denote a variable, which both backends assume is impossible.
Minimal repro — one file, main.fpy, compiled with -i .:
import main
g: U32 = 5
x: U32 = main.g
Semantic analysis passes; codegen crashes with an unhandled Python exception rather than a diagnostic:
- fpybc:
AssertionError: VariableSymbol(name=Token('NAME', 'g'), ... is_global=True) at the assert False in emit_AstGetAttr (src/fpy/codegen_fpybc.py), whose comment reads "A qualified name can't denote a variable (an imported sequence may not declare a top-level variable), so sym is never a VariableSymbol"
- wasm:
AttributeError: 'VariableSymbol' object has no attribute 'parent_expr' in _emit_ptr
The realistic version is two sequences in a directory that import each other, one of which is the entry point:
# lib.fpy
import main
def f():
main.g = 9 # compiles on fpybc, crashes the wasm backend
def r() -> U32:
return main.g # crashes both backends
Where it doesn't crash it works, which is the other half of the problem: on fpybc the write above really does store 9 into the importer's global, and
# lib.fpy
from main import *
def f() -> U32:
return g
compiles and runs on both backends, returning the importer's g — which is what test_imported_function_cannot_see_importer_globals says must not happen.
Per SPEC.md Imports step 2, an import that resolves to the main sequence is skipped, so the "an imported sequence may contain only function definitions and imports" check never runs on it — but
BindImportsstill associates the name with that sequence's definitions. The main sequence is the only one allowed to declare top-level variables, so a qualified name can now denote a variable, which both backends assume is impossible.Minimal repro — one file,
main.fpy, compiled with-i .:Semantic analysis passes; codegen crashes with an unhandled Python exception rather than a diagnostic:
AssertionError: VariableSymbol(name=Token('NAME', 'g'), ... is_global=True)at theassert Falseinemit_AstGetAttr(src/fpy/codegen_fpybc.py), whose comment reads "A qualified name can't denote a variable (an imported sequence may not declare a top-level variable), so sym is never a VariableSymbol"AttributeError: 'VariableSymbol' object has no attribute 'parent_expr'in_emit_ptrThe realistic version is two sequences in a directory that import each other, one of which is the entry point:
Where it doesn't crash it works, which is the other half of the problem: on fpybc the write above really does store 9 into the importer's global, and
compiles and runs on both backends, returning the importer's
g— which is whattest_imported_function_cannot_see_importer_globalssays must not happen.