Skip to content

Commit 13336f4

Browse files
authored
Allow recursive def references inside def init values (#578)
1 parent 29da93b commit 13336f4

File tree

3 files changed

+22
-5
lines changed

3 files changed

+22
-5
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
* Added support for auto-resolving namespaces for keyword from the current namespace using the `::kw` syntax (#576)
1010
* Added support for namespaced map syntax (#577)
1111

12+
### Fixed
13+
* Fixed a bug where `def` forms did not permit recursive references to the `def`'ed Vars (#578)
14+
1215
## [v0.1.dev14] - 2020-06-18
1316
### Added
1417
* Added support for `future`s (#441)

src/basilisp/lang/compiler/analyzer.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -838,19 +838,18 @@ def _def_ast( # pylint: disable=too-many-branches,too-many-locals
838838
f"def names must be symbols, not {type(name)}", form=name
839839
)
840840

841+
init_idx: Optional[int]
841842
children: vec.Vector[kw.Keyword]
842843
if nelems == 2:
843-
init = None
844+
init_idx = None
844845
doc = None
845846
children = vec.Vector.empty()
846847
elif nelems == 3:
847-
with ctx.expr_pos():
848-
init = _analyze_form(ctx, runtime.nth(form, 2))
848+
init_idx = 2
849849
doc = None
850850
children = vec.v(INIT)
851851
else:
852-
with ctx.expr_pos():
853-
init = _analyze_form(ctx, runtime.nth(form, 3))
852+
init_idx = 3
854853
doc = runtime.nth(form, 2)
855854
if not isinstance(doc, str):
856855
raise AnalyzerException("def docstring must be a string", form=doc)
@@ -918,6 +917,15 @@ def _def_ast( # pylint: disable=too-many-branches,too-many-locals
918917
dynamic=def_meta.val_at(SYM_DYNAMIC_META_KEY, False), # type: ignore
919918
meta=var_meta,
920919
)
920+
921+
# Set the value after interning the Var so the symbol is available for
922+
# recursive definition.
923+
if init_idx is not None:
924+
with ctx.expr_pos():
925+
init = _analyze_form(ctx, runtime.nth(form, init_idx))
926+
else:
927+
init = None
928+
921929
descriptor = Def(
922930
form=form,
923931
name=bare_name,

tests/basilisp/compiler_test.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,12 @@ def test_def_unbound(self, lcompile: CompileFn, ns: runtime.Namespace):
288288
assert var.root == runtime.Unbound(var)
289289
assert not var.is_bound
290290

291+
def test_recursive_def(self, lcompile: CompileFn, ns: runtime.Namespace):
292+
lcompile("(def a a)")
293+
var = Var.find_in_ns(sym.symbol(ns.name), sym.symbol("a"))
294+
assert var.root == runtime.Unbound(var)
295+
assert var.is_bound
296+
291297
def test_def_number_of_elems(self, lcompile: CompileFn, ns: runtime.Namespace):
292298
with pytest.raises(compiler.CompilerException):
293299
lcompile("(def)")

0 commit comments

Comments
 (0)