Skip to content

Commit dfe00a9

Browse files
timfennisclaude
andcommitted
Small cleanups in ndc_analyser: unreachable!, stale comments, docs
Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 1a6a7ce commit dfe00a9

3 files changed

Lines changed: 16 additions & 44 deletions

File tree

ndc_analyser/REVIEW.md

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,3 @@
2727
collects exact matches, loose matches, and all-by-name simultaneously would improve compile-time
2828
performance for programs with many overloads.
2929

30-
## Small: Cleanup
31-
32-
- **`debug_assert!(false)``unreachable!`** (`src/scope.rs` ~line 98)
33-
A variadic function match should be impossible at this call-site. Replace with `unreachable!`
34-
once confident the invariant holds.
35-
36-
- **`new_iteration_scope` identical to `new_block_scope`** (`src/scope.rs` ~line 46)
37-
Both constructors produce identical `Scope` values. Merge them, or add a comment explaining why
38-
the distinction exists for future work (e.g., break/continue scoping).
39-
40-
- **Anonymous slot uses magic string `"\x00"`** (`src/scope.rs` ~line 456)
41-
`reserve_anonymous_slot` uses `"\x00"` as a sentinel name. An `Option<String>` name field would
42-
be more explicit, though this works since the lexer never produces null bytes.
43-
44-
- **Stale comment on `Return` analysis** (`src/analyser.rs` ~line 255)
45-
Remove the "Actually it doesn't seem to make it any easier" comment.
46-
47-
- **Commented-out debug println** (`src/analyser.rs` ~line 287)
48-
Remove `// println!("resolve fn {name} {}", ...)`.
49-
50-
- **Unnecessary clone of `StaticType::Any`** (`src/analyser.rs` ~line 490)
51-
`resolved_type.clone()` on a unit variant — just push `StaticType::Any` directly.
52-
53-
- **Missing comment on `from_global_scope` dual-root design** (`src/scope.rs` ~line 145)
54-
`global_scope` is separate from `scopes[0]` — add a comment explaining why there are two root
55-
scopes (one for natives, one for user top-level code).

ndc_analyser/src/analyser.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,6 @@ impl Analyser {
236236
value: Box::new(value_type.unwrap_or_else(StaticType::unit)),
237237
})
238238
}
239-
// Return evaluates to the type of the expression it returns, which makes type checking easier!
240-
// Actually it doesn't seem to make it any easier
241239
Expression::Return { value } => self.analyse(value),
242240
Expression::RangeInclusive { start, end }
243241
| Expression::RangeExclusive { start, end } => {
@@ -268,8 +266,6 @@ impl Analyser {
268266
return self.analyse(ident);
269267
};
270268

271-
// println!("resolve fn {name} {}", argument_types.iter().join(", "));
272-
273269
let binding = self
274270
.scope_tree
275271
.resolve_function_binding(name, argument_types);
@@ -448,15 +444,14 @@ impl Analyser {
448444
let mut seen_names: Vec<&str> = Vec::new();
449445

450446
for param in parameters {
451-
let resolved_type = StaticType::Any;
452-
types.push(resolved_type.clone());
447+
types.push(StaticType::Any);
453448
if seen_names.contains(&param.name.as_str()) {
454449
return Err(AnalysisError::parameter_redefined(&param.name, span));
455450
}
456451
seen_names.push(&param.name);
457452

458453
self.scope_tree
459-
.create_local_binding(param.name.clone(), resolved_type);
454+
.create_local_binding(param.name.clone(), StaticType::Any);
460455
}
461456

462457
Ok(types)

ndc_analyser/src/scope.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,14 @@ impl Scope {
4343
}
4444
}
4545

46+
/// Identical to `new_block_scope` today — kept as a separate constructor so that
47+
/// iteration-specific behaviour (e.g. break/continue scoping) can be added later.
4648
pub(crate) fn new_iteration_scope(
4749
parent_idx: Option<usize>,
4850
base_offset: usize,
4951
function_scope_idx: usize,
5052
) -> Self {
51-
Self {
52-
parent_idx,
53-
creates_environment: false,
54-
base_offset,
55-
function_scope_idx,
56-
identifiers: Vec::default(),
57-
upvalues: Vec::default(),
58-
}
53+
Self::new_block_scope(parent_idx, base_offset, function_scope_idx)
5954
}
6055

6156
pub(crate) fn find_slot_by_name(&self, find_ident: &str) -> Option<usize> {
@@ -94,9 +89,7 @@ impl Scope {
9489
};
9590

9691
let Some(param_types) = parameters else {
97-
// If this branch happens then the function we're matching against is variadic meaning it's always a match
98-
debug_assert!(false, "we should never be calling find_function_candidates if there were variadic matches");
99-
return Some(slot);
92+
unreachable!("find_function_candidates should never be called when there are variadic matches");
10093
};
10194

10295
let is_good = param_types.len() == find_types.len()
@@ -142,6 +135,13 @@ pub struct ScopeTree {
142135
}
143136

144137
impl ScopeTree {
138+
/// Build a `ScopeTree` seeded with pre-registered global bindings (native functions etc.).
139+
///
140+
/// Two root scopes exist by design: `global_scope` holds native/built-in bindings that are
141+
/// always accessible, while `scopes[0]` is the user's top-level function scope where
142+
/// user-defined declarations land. This separation keeps native bindings out of the
143+
/// mutable scope chain so they can be searched as a fallback without interfering with
144+
/// user-level shadowing.
145145
pub fn from_global_scope(global_scope_map: Vec<(String, StaticType)>) -> Self {
146146
let mut global_scope = Scope::new_function_scope(None, 0);
147147
global_scope.identifiers = global_scope_map;
@@ -406,6 +406,9 @@ impl ScopeTree {
406406
/// Used to allocate the list/map accumulator before analysing the body of a
407407
/// for-comprehension, so that any nested comprehensions receive strictly
408408
/// higher slot numbers and cannot collide with this accumulator.
409+
///
410+
/// Uses `"\x00"` as a sentinel name that can never collide with user identifiers
411+
/// since the lexer never produces null bytes.
409412
pub(crate) fn reserve_anonymous_slot(&mut self) -> usize {
410413
self.scopes[self.current_scope_idx].allocate("\x00".to_string(), StaticType::Any)
411414
}

0 commit comments

Comments
 (0)