Skip to content

Commit 7937e1f

Browse files
committed
fix(react_compiler): preserve bailout diagnostic severity
1 parent 6f2027e commit 7937e1f

13 files changed

Lines changed: 79 additions & 56 deletions

crates/oxc_react_compiler/src/diagnostics.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -122,30 +122,6 @@ pub fn has_critical_errors(diagnostics: &[OxcDiagnostic]) -> bool {
122122
.any(|d| d.severity == Severity::Error && !ErrorCategory::PreserveManualMemo.matches(d))
123123
}
124124

125-
/// Format a thrown diagnostic as a string matching the TS
126-
/// `CompilerError.toString()` output, used for the `data` field of
127-
/// `CompileUnexpectedThrow` events: `"<Heading>: <reason>. <description>."`.
128-
/// The reason is the message minus the deterministic prefix added by
129-
/// [`ErrorCategory::diagnostic`].
130-
pub fn to_string_for_event(diagnostic: &OxcDiagnostic) -> String {
131-
let category = ErrorCategory::of(diagnostic);
132-
let heading = match category {
133-
Some("IncompatibleLibrary" | "PreserveManualMemo" | "UnsupportedSyntax") => {
134-
"Compilation Skipped"
135-
}
136-
Some(heading @ ("Invariant" | "Todo")) => heading,
137-
_ => "Error",
138-
};
139-
let reason = category
140-
.and_then(|c| diagnostic.message.strip_prefix(&format!("[ReactCompiler] {c}: ")))
141-
.unwrap_or(&diagnostic.message);
142-
let mut buf = format!("{heading}: {reason}");
143-
if let Some(help) = &diagnostic.help {
144-
buf.push_str(&format!(". {help}."));
145-
}
146-
buf
147-
}
148-
149125
/// Owned copy of a diagnostic for the log accumulator, labelling the enclosing
150126
/// function (`fn_span`) when the diagnostic carries no location of its own.
151127
#[cold]

crates/oxc_react_compiler/src/react_compiler/entrypoint/pipeline.rs

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@
1010
1111
use oxc_allocator::GetAllocator;
1212
use oxc_diagnostics::{Diagnostics, OxcDiagnostic};
13-
use oxc_span::Span;
1413

15-
use crate::diagnostics::{ErrorCategory, to_string_for_event};
14+
use crate::diagnostics::ErrorCategory;
1615
use crate::react_compiler_hir::ReactFunctionType;
1716
use crate::react_compiler_hir::environment::Environment;
1817
use crate::react_compiler_hir::environment::OutputMode;
@@ -91,9 +90,6 @@ use crate::options::CompilerOutputMode;
9190
/// Run the compilation pipeline on a single function.
9291
///
9392
/// On failure, returns the diagnostics of the failed compilation attempt.
94-
/// An error thrown by a pass (in TS: an exception escaping the pass) that is
95-
/// not an Invariant additionally surfaces a `CompileUnexpectedThrow`
96-
/// diagnostic, matching TS `tryCompileFunction`'s catch block.
9793
#[allow(clippy::too_many_arguments)]
9894
pub fn compile_fn<'a>(
9995
ast: &oxc_ast::builder::AstBuilder<'a>,
@@ -103,32 +99,19 @@ pub fn compile_fn<'a>(
10399
mode: CompilerOutputMode,
104100
env_config: &EnvironmentConfig,
105101
context: &mut ProgramContext<'a>,
106-
fn_span: Option<Span>,
107102
) -> Result<Option<CodegenFunction<'a>>, Diagnostics> {
108103
match run_pipeline(ast, func, scope, fn_type, mode, env_config, context) {
109104
Ok(result) => result,
110-
Err(thrown) => {
111-
if !ErrorCategory::Invariant.matches(&thrown) {
112-
let mut diagnostic = OxcDiagnostic::error(format!(
113-
"[ReactCompiler] Unexpected error: {}",
114-
to_string_for_event(&thrown)
115-
));
116-
if let Some(span) = fn_span {
117-
diagnostic = diagnostic.with_label(span);
118-
}
119-
context.diagnostics.push(diagnostic);
120-
}
121-
Err(Diagnostics::from(thrown))
122-
}
105+
Err(diagnostic) => Err(Diagnostics::from(diagnostic)),
123106
}
124107
}
125108

126109
/// The pass pipeline: creates an Environment, runs BuildHIR (lowering), the
127110
/// HIR/reactive-scope passes, and codegen.
128111
///
129-
/// `Err(OxcDiagnostic)` is an error thrown by a pass (a TS exception);
112+
/// `Err(OxcDiagnostic)` is a diagnostic that immediately bails out of a pass.
130113
/// Invariant and end-of-pipeline accumulated errors return as
131-
/// `Ok(Err(diagnostics))` since they must not surface `CompileUnexpectedThrow`.
114+
/// `Ok(Err(diagnostics))`.
132115
#[allow(clippy::too_many_arguments)]
133116
fn run_pipeline<'a>(
134117
ast: &oxc_ast::builder::AstBuilder<'a>,

crates/oxc_react_compiler/src/react_compiler/entrypoint/program.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,8 +1056,7 @@ fn try_compile_function<'a>(
10561056
env_config: &EnvironmentConfig,
10571057
context: &mut ProgramContext<'a>,
10581058
) -> Result<Option<CodegenFunction<'a>>, Diagnostics> {
1059-
// Check for suppressions that affect this function. Suppression errors are
1060-
// returned (not thrown), so they do NOT trigger CompileUnexpectedThrow.
1059+
// Check for suppressions that affect this function before entering the pipeline.
10611060
if let (Some(start), Some(end)) = (source.fn_start, source.fn_end) {
10621061
let affecting = filter_suppressions_that_affect_function(&context.suppressions, start, end);
10631062
if !affecting.is_empty() {
@@ -1075,7 +1074,6 @@ fn try_compile_function<'a>(
10751074
output_mode,
10761075
env_config,
10771076
context,
1078-
source.fn_ast_span,
10791077
)
10801078
}
10811079

crates/oxc_react_compiler/tests/snapshots/error.dont-hoist-inline-reference.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ input_file: crates/oxc_react_compiler/fixtures/error.dont-hoist-inline-reference
44
---
55
Diagnostics:
66

7-
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Unexpected error: Todo: [hoisting] EnterSSA: Expected identifier to be defined before being used. Identifier x$1 is undefined.", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(41), length: 62 }, primary: false }]), help: None, note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } }
87
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Todo: [hoisting] EnterSSA: Expected identifier to be defined before being used", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(67), length: 22 }, primary: false }]), help: Some("Identifier x$1 is undefined"), note: None, severity: Warning, code: OxcCode { scope: None, number: None }, url: None } }
98

109
No changes.

crates/oxc_react_compiler/tests/snapshots/error.invalid-known-incompatible-function.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ input_file: crates/oxc_react_compiler/fixtures/error.invalid-known-incompatible-
44
---
55
Diagnostics:
66

7-
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Unexpected error: Compilation Skipped: Use of incompatible library. This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized.", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(71), length: 87 }, primary: false }]), help: None, note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } }
87
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] IncompatibleLibrary: Use of incompatible library", labels: One([LabeledSpan { label: Some("useKnownIncompatible is known to be incompatible"), span: SourceSpan { offset: SourceOffset(109), length: 17 }, primary: false }]), help: Some("This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized"), note: None, severity: Warning, code: OxcCode { scope: None, number: None }, url: None } }
98

109
No changes.

crates/oxc_react_compiler/tests/snapshots/error.invalid-known-incompatible-hook-return-property.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ input_file: crates/oxc_react_compiler/fixtures/error.invalid-known-incompatible-
44
---
55
Diagnostics:
66

7-
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Unexpected error: Compilation Skipped: Use of incompatible library. This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized.", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(82), length: 119 }, primary: false }]), help: None, note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } }
87
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] IncompatibleLibrary: Use of incompatible library", labels: One([LabeledSpan { label: Some("useKnownIncompatibleIndirect returns an incompatible() function that is known incompatible"), span: SourceSpan { offset: SourceOffset(177), length: 12 }, primary: false }]), help: Some("This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized"), note: None, severity: Warning, code: OxcCode { scope: None, number: None }, url: None } }
98

109
No changes.

crates/oxc_react_compiler/tests/snapshots/error.invalid-known-incompatible-hook.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ input_file: crates/oxc_react_compiler/fixtures/error.invalid-known-incompatible-
44
---
55
Diagnostics:
66

7-
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Unexpected error: Compilation Skipped: Use of incompatible library. This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized.", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(74), length: 90 }, primary: false }]), help: None, note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } }
87
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] IncompatibleLibrary: Use of incompatible library", labels: One([LabeledSpan { label: Some("useKnownIncompatible is known to be incompatible"), span: SourceSpan { offset: SourceOffset(112), length: 20 }, primary: false }]), help: Some("This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized"), note: None, severity: Warning, code: OxcCode { scope: None, number: None }, url: None } }
98

109
No changes.

crates/oxc_react_compiler/tests/snapshots/error.todo-functiondecl-hoisting.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ input_file: crates/oxc_react_compiler/fixtures/error.todo-functiondecl-hoisting.
44
---
55
Diagnostics:
66

7-
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Unexpected error: Todo: [PruneHoistedContexts] Rewrite hoisted function references", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(330), length: 164 }, primary: false }]), help: None, note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } }
87
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Todo: [PruneHoistedContexts] Rewrite hoisted function references", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(371), length: 3 }, primary: false }]), help: None, note: None, severity: Warning, code: OxcCode { scope: None, number: None }, url: None } }
98

109
No changes.

crates/oxc_react_compiler/tests/snapshots/error.todo-hook-call-spreads-mutable-iterator.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ input_file: crates/oxc_react_compiler/fixtures/error.todo-hook-call-spreads-muta
44
---
55
Diagnostics:
66

7-
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Unexpected error: Todo: Support spread syntax for hook arguments", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(45), length: 120 }, primary: false }]), help: None, note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } }
87
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Todo: Support spread syntax for hook arguments", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(147), length: 14 }, primary: false }]), help: None, note: None, severity: Warning, code: OxcCode { scope: None, number: None }, url: None } }
98

109
No changes.

crates/oxc_react_compiler/tests/snapshots/error.todo-rust-as-expression-assignment-target.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ input_file: crates/oxc_react_compiler/fixtures/error.todo-rust-as-expression-ass
44
---
55
Diagnostics:
66

7-
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Unexpected error: Todo: [FindContextIdentifiers] Cannot handle Object destructuring assignment target TSAsExpression", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(0), length: 137 }, primary: false }]), help: None, note: None, severity: Error, code: OxcCode { scope: None, number: None }, url: None } }
87
OxcDiagnostic { inner: OxcDiagnosticInner { message: "[ReactCompiler] Todo: [FindContextIdentifiers] Cannot handle Object destructuring assignment target TSAsExpression", labels: One([LabeledSpan { label: None, span: SourceSpan { offset: SourceOffset(52), length: 32 }, primary: false }]), help: None, note: None, severity: Warning, code: OxcCode { scope: None, number: None }, url: None } }
98

109
No changes.

0 commit comments

Comments
 (0)