1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
//! S2 T3: port of `hermes::sema::Unresolver` — declared at
//! SemanticResolver.h:681-713, defined at SemanticResolver.cpp:3216-3240.
//!
//! "Visitor pass for marking variables as Unresolvable based on local
//! `eval()` or `with`" (SemanticResolver.h:681-682).
//!
//! ## Why it exists
//!
//! A `with` block (and, once it is supported, a non-strict direct `eval`)
//! can introduce bindings that are only known at run time, so any identifier
//! *inside* it that the resolver already resolved to a declaration in an
//! enclosing scope may in fact be shadowed dynamically. Such identifiers
//! must not keep a static resolution: this pass walks the affected subtree,
//! clears each such identifier's "expression decl" and sets its
//! `unresolvable` flag, which is what makes later stages emit a dynamic
//! (by-name) lookup instead of a variable access.
//!
//! ## The two call sites
//!
//! - `visit(WithStatementNode *)` (cpp:763-768) — ported in
//! `statements.rs`, and the only one reachable today. It passes
//! `curScope_->depth + 1` and the `with`'s BODY as the root, so
//! declarations made *inside* the `with` (depth >= that) keep their
//! resolution while everything from the enclosing scope outwards loses it.
//! - `visitFunctionBodyAfterParamsVisited` (cpp:1960-1967) — the local-`eval`
//! case, which C++ itself disables: the call sits under a literal
//! `if ((false))` — the doubled parentheses say the constant is
//! deliberate — behind a `TODO: enable this when non-strict direct eval is
//! supported`. (Upstream briefly spelled it `#if 0` for a Windows clang17
//! `-Wunreachable-code` warning and backed that out in `6fbc3706d`; the
//! block is dead in every spelling.) `functions.rs` carries that dead
//! branch's TODO at the matching site; nothing calls this pass from there
//! in either tree.
//!
//! ## Dump visibility
//!
//! `unresolvable` IS printed — `hermes_sema::dump` appends ` UNR` to the
//! identifier line and suppresses the `[...]` decl bracket
//! (SemResolve.cpp:125-126, `dump.rs`'s `enter_identifier`) — but the
//! differential cannot see it through a `with`, because
//! `visit(WithStatementNode *)` reports "with statement is not supported"
//! whenever `compile_` is set and hermesc then exits before dumping anything
//! (verified against `hermesc -dump-sema`: stdout empty, exit code 2). So
//! `error-with.js` in the corpus pins only the diagnostic and the exit code,
//! and `tests/resolver.rs`'s
//! `with_statement_unresolves_identifiers_above_its_depth` is what pins this
//! pass's actual effect, including the ` UNR` rendering.
//!
//! ## Deviations
//!
//! - C++ dispatches through `visitESTreeNodeNoReplace` and therefore has to
//! supply no-op `incRecursionDepth`/`decRecursionDepth` hooks
//! (SemanticResolver.h:695-700). This port's read-only
//! [`hermes_ast::visitor::Visitor`] has no depth hooks at all, so those two
//! members have no counterpart.
//! - C++'s generic `visit(Node *)` overload (SemanticResolver.h:689-691) and
//! its `visit(IdentifierNode *)` overload become the two arms of the single
//! `visit_node` below, exactly as `mod.rs`'s `DeclHoisting` does it.
//! - The constructor is private in C++ (`run` is the only entry point); here
//! it is inlined into [`Unresolver::run`] for the same effect.
use ;
use Visitor;
use crateSemContext;
/// Port of `hermes::sema::Unresolver` (SemanticResolver.h:683-713).
pub