Skip to content

Commit 73b8b83

Browse files
authored
Don't force all top-level do forms to use Var indirection (#1033)
Fixes #1034
1 parent a9b1883 commit 73b8b83

File tree

6 files changed

+22
-14
lines changed

6 files changed

+22
-14
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Changed
9+
* The compiler will no longer require `Var` indirection for top-level `do` forms unless those forms specify `^:use-var-indirection` metadata (which currently is only used in the `ns` macro) (#1034)
10+
811
### Fixed
912
* Fix a bug where the compiler would always generate inline function definitions even if the `inline-functions` compiler option is disabled (#1023)
1013
* Fix a bug where `defrecord`/`deftype` constructors could not be used in the type's methods. (#1025)

src/basilisp/core.lpy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5189,7 +5189,7 @@
51895189
(map (fn [v]
51905190
`(import ~v))
51915191
(:import opts)))]
5192-
`(do
5192+
`(^:use-var-indirection do
51935193
(in-ns (quote ~name))
51945194
(swap! *loaded-libs* conj (quote ~name))
51955195
~(when doc

src/basilisp/lang/compiler/analyzer.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
SYM_REDEF_META_KEY,
7878
SYM_STATICMETHOD_META_KEY,
7979
SYM_TAG_META_KEY,
80+
SYM_USE_VAR_INDIRECTION_KEY,
8081
VAR_IS_PROTOCOL_META_KEY,
8182
SpecialForm,
8283
)
@@ -673,6 +674,7 @@ def get_meta_prop(o: Union[IMeta, Var]) -> Any:
673674
_is_py_staticmethod = _bool_meta_getter(SYM_STATICMETHOD_META_KEY)
674675
_is_macro = _bool_meta_getter(SYM_MACRO_META_KEY)
675676
_is_no_inline = _bool_meta_getter(SYM_NO_INLINE_META_KEY)
677+
_is_use_var_indirection = _bool_meta_getter(SYM_USE_VAR_INDIRECTION_KEY)
676678
_inline_meta = _meta_getter(SYM_INLINE_META_KW)
677679
_tag_meta = _meta_getter(SYM_TAG_META_KEY)
678680

@@ -2017,6 +2019,7 @@ def _do_ast(form: ISeq, ctx: AnalyzerContext) -> Do:
20172019
form=form,
20182020
statements=vec.vector(statements),
20192021
ret=ret,
2022+
use_var_indirection=_is_use_var_indirection(form.first),
20202023
env=ctx.get_node_env(pos=ctx.syntax_position),
20212024
)
20222025

src/basilisp/lang/compiler/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class SpecialForm:
5151
SYM_REDEF_META_KEY = kw.keyword("redef")
5252
SYM_STATICMETHOD_META_KEY = kw.keyword("staticmethod")
5353
SYM_TAG_META_KEY = kw.keyword("tag")
54+
SYM_USE_VAR_INDIRECTION_KEY = kw.keyword("use-var-indirection")
5455

5556
ARGLISTS_KW = kw.keyword("arglists")
5657
INTERFACE_KW = kw.keyword("interface")

src/basilisp/lang/compiler/generator.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,18 +1530,18 @@ def _wrap_override_var_indirection(
15301530
) -> "PyASTGenerator[T_node, P_generator, T_pynode]":
15311531
"""
15321532
Wrap a Node generator to apply a special override requiring Var indirection
1533-
for any Var accesses generated within top-level `do` blocks.
1534-
1535-
This is a bit of a hack to account for the `ns` macro, which is the first
1536-
form in most standard Namespaces. When Basilisp `require`s a Namespace, it
1537-
(like in Clojure) simply loads the file and lets that Namespace's `ns` macro
1538-
create the new Namespace and perform any setup. However, the Basilisp
1539-
compiler desperately tries to emit "smarter" Python code which avoids using
1540-
`Var.find` whenever the resolved symbol can be safely called directly from
1541-
the generated Pythom module. Without this hack, the compiler will emit code
1542-
during macroexpansion to access `basilisp.core` functions used in the `ns`
1543-
macro directly, even though they will not be available yet in the target
1544-
Namespace module.
1533+
for any Var accesses generated within `do` blocks which are marked with the
1534+
^:use-var-indirection metadata.
1535+
1536+
This is needed to account for the `ns` macro, which is the first form in most
1537+
standard Namespaces. When Basilisp `require`s a Namespace, it (like in Clojure)
1538+
simply loads the file and lets that Namespace's `ns` macro create the new
1539+
Namespace and perform any setup. However, the Basilisp compiler desperately
1540+
tries to emit "smarter" Python code which avoids using `Var.find` whenever
1541+
the resolved symbol can be safely called directly from the generated Python
1542+
module. Without this hack, the compiler will emit code during macroexpansion
1543+
to access `basilisp.core` functions used in the `ns` macro directly, even
1544+
though they will not be available yet in the target Namespace module.
15451545
"""
15461546

15471547
@wraps(f)
@@ -1551,7 +1551,7 @@ def _wrapped_do(
15511551
*args: P_generator.args,
15521552
**kwargs: P_generator.kwargs,
15531553
) -> GeneratedPyAST[T_pynode]:
1554-
if isinstance(node, Do) and node.top_level:
1554+
if isinstance(node, Do) and node.use_var_indirection:
15551555
with ctx.with_var_indirection_override():
15561556
return f(ctx, cast(T_node, node), *args, **kwargs)
15571557
else:

src/basilisp/lang/compiler/nodes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ class Do(Node[SpecialForm]):
532532
ret: Node
533533
env: NodeEnv
534534
is_body: bool = False
535+
use_var_indirection: bool = False
535536
children: Sequence[kw.Keyword] = vec.v(STATEMENTS, RET)
536537
op: NodeOp = NodeOp.DO
537538
top_level: bool = False

0 commit comments

Comments
 (0)