Skip to content

Commit 8435daf

Browse files
Brooooooklynclaude
andauthored
fix(angular): use fail-fast error handling for invariant violations and remove panics (#37)
- Make i18n metadata type checks fail-fast (return early) instead of silently dropping placeholders, matching Angular's throw behavior - Make unknown @for loop variable checks fail-fast instead of emitting empty expressions, matching Angular's AssertionError throw - Add 4 unit tests for the fail-fast behavior - Replace all panic!/unreachable!/debug_assert! in production code with diagnostics-style error reporting or safe fallbacks (10 instances) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7828f59 commit 8435daf

File tree

10 files changed

+301
-103
lines changed

10 files changed

+301
-103
lines changed

crates/oxc_angular_compiler/src/i18n/ast.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,7 @@ impl Visitor for CloneVisitor {
575575
Node::IcuPlaceholder(IcuPlaceholder::new(icu, ph.name.clone(), ph.source_span.clone()))
576576
} else {
577577
// visit_icu should always return Node::Icu by design.
578-
// This is a compiler bug if we reach here.
579-
debug_assert!(false, "visit_icu should return Node::Icu");
580-
// Return the original placeholder unchanged as fallback
578+
// Return the original placeholder unchanged as a safe fallback.
581579
Node::IcuPlaceholder(ph.clone())
582580
}
583581
}

crates/oxc_angular_compiler/src/output/ast.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,12 +1389,7 @@ impl<'a> OutputExpression<'a> {
13891389
OutputExpression::WrappedIrNode(_) => {
13901390
// WrappedIrNode expressions wrap IR expressions for deferred processing.
13911391
// They should be resolved during the reify phase before any cloning occurs.
1392-
// If we hit this, it's a compiler bug.
1393-
debug_assert!(
1394-
false,
1395-
"Cannot clone a WrappedIrExpr. WrappedIrExpr should be resolved before cloning."
1396-
);
1397-
// Return a placeholder undefined literal
1392+
// Return a placeholder undefined literal as a safe fallback.
13981393
OutputExpression::Literal(Box::new_in(
13991394
LiteralExpr { value: LiteralValue::Undefined, source_span: None },
14001395
allocator,

crates/oxc_angular_compiler/src/output/emitter.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ impl EmitterContext {
113113
/// Lines is always non-empty: initialized with one element in `new()`,
114114
/// and `println()` only pushes (never pops below 1).
115115
fn current_line(&self) -> &EmittedLine {
116-
debug_assert!(!self.lines.is_empty(), "lines should never be empty");
116+
// Invariant: lines is always non-empty (initialized with one element in new(),
117+
// and println() only pushes, never pops below 1).
117118
&self.lines[self.lines.len() - 1]
118119
}
119120

@@ -123,7 +124,8 @@ impl EmitterContext {
123124
/// Lines is always non-empty: initialized with one element in `new()`,
124125
/// and `println()` only pushes (never pops below 1).
125126
fn current_line_mut(&mut self) -> &mut EmittedLine {
126-
debug_assert!(!self.lines.is_empty(), "lines should never be empty");
127+
// Invariant: lines is always non-empty (initialized with one element in new(),
128+
// and println() only pushes, never pops below 1).
127129
let len = self.lines.len();
128130
&mut self.lines[len - 1]
129131
}

0 commit comments

Comments
 (0)