mirror of
https://github.com/facebook/react.git
synced 2026-02-21 19:31:52 +00:00
[compiler] Phase 3: Make lower() always produce HIRFunction
This commit is contained in:
@@ -75,49 +75,49 @@ Change `runWithEnvironment` to run all passes and check for errors at the end in
|
||||
|
||||
Currently `lower()` returns `Result<HIRFunction, CompilerError>`. It already accumulates errors internally via `builder.errors`, but returns `Err` when errors exist. Change it to always return `Ok(hir)` while recording errors on the environment.
|
||||
|
||||
- [ ] **3.1 Change `lower` to always return HIRFunction** (`src/HIR/BuildHIR.ts`)
|
||||
- [x] **3.1 Change `lower` to always return HIRFunction** (`src/HIR/BuildHIR.ts`)
|
||||
- Change return type from `Result<HIRFunction, CompilerError>` to `HIRFunction`
|
||||
- Instead of returning `Err(builder.errors)` at line 227-229, record errors on `env` via `env.recordError(builder.errors)` and return the (partial) HIR
|
||||
- Instead of returning `Err(builder.errors)` at line 227-229, record errors on `env` via `env.recordErrors(builder.errors)` and return the (partial) HIR
|
||||
- Update the pipeline to call `lower(func, env)` directly instead of `lower(func, env).unwrap()`
|
||||
- Added try/catch around body lowering to catch thrown CompilerErrors (e.g., from `resolveBinding`) and record them
|
||||
|
||||
- [ ] **3.2 Handle `var` declarations as `let`** (`src/HIR/BuildHIR.ts`, line ~855)
|
||||
- Currently throws `Todo("Handle var kinds in VariableDeclaration")`
|
||||
- Instead: record the Todo error on env, then treat the `var` as `let` and continue lowering
|
||||
- [x] **3.2 Handle `var` declarations as `let`** (`src/HIR/BuildHIR.ts`, line ~855)
|
||||
- Record the Todo error, then treat `var` as `let` and continue lowering (instead of skipping the declaration)
|
||||
|
||||
- [ ] **3.3 Handle `try/finally` by pruning `finally`** (`src/HIR/BuildHIR.ts`, lines ~1281-1296)
|
||||
- Currently throws Todo for `try` without `catch` and `try` with `finally`
|
||||
- Instead: record the Todo error, then lower the `try/catch` portion only (put the `finally` block content in the fallthrough of the try/catch)
|
||||
- [x] **3.3 Handle `try/finally` by pruning `finally`** (`src/HIR/BuildHIR.ts`, lines ~1281-1296)
|
||||
- Already handled: `try` without `catch` pushes error and returns; `try` with `finally` pushes error and continues with `try/catch` portion only
|
||||
|
||||
- [ ] **3.4 Handle `eval()` via UnsupportedNode** (`src/HIR/BuildHIR.ts`, line ~3568)
|
||||
- Currently throws `UnsupportedSyntax("The 'eval' function is not supported")`
|
||||
- Instead: record the error, emit an `UnsupportedNode` instruction value with the original AST node
|
||||
- [x] **3.4 Handle `eval()` via UnsupportedNode** (`src/HIR/BuildHIR.ts`, line ~3568)
|
||||
- Already handled: records error via `builder.errors.push()` and continues
|
||||
|
||||
- [ ] **3.5 Handle `with` statement via UnsupportedNode** (`src/HIR/BuildHIR.ts`, line ~1382)
|
||||
- Currently throws `UnsupportedSyntax`
|
||||
- Instead: record the error, emit the body statements as-is (or skip them), continue
|
||||
- [x] **3.5 Handle `with` statement via UnsupportedNode** (`src/HIR/BuildHIR.ts`, line ~1382)
|
||||
- Already handled: records error and emits `UnsupportedNode`
|
||||
|
||||
- [ ] **3.6 Handle inline `class` declarations** (`src/HIR/BuildHIR.ts`, line ~1402)
|
||||
- Currently throws `UnsupportedSyntax`
|
||||
- Already creates an `UnsupportedNode`; just record the error instead of throwing
|
||||
- [x] **3.6 Handle inline `class` declarations** (`src/HIR/BuildHIR.ts`, line ~1402)
|
||||
- Already handled: records error and emits `UnsupportedNode`
|
||||
|
||||
- [ ] **3.7 Handle remaining Todo errors in expression lowering** (`src/HIR/BuildHIR.ts`)
|
||||
- For each of the ~35 Todo error sites in `lowerExpression`, `lowerAssignment`, `lowerMemberExpression`, etc.:
|
||||
- Record the Todo error on the environment
|
||||
- Emit an `UnsupportedNode` instruction value with the original Babel AST node as fallback
|
||||
- Key sites include: pipe operator, tagged templates with interpolations, compound logical assignment (`&&=`, `||=`, `??=`), `for await...of`, object getters/setters, UpdateExpression on context variables, complex destructuring patterns
|
||||
- The `UnsupportedNode` variant already exists in HIR and passes through codegen unchanged, so no new HIR types are needed for most cases
|
||||
- [x] **3.7 Handle remaining Todo errors in expression lowering** (`src/HIR/BuildHIR.ts`)
|
||||
- Already handled: all ~60 error sites use `builder.errors.push()` to accumulate errors. The try/catch around body lowering provides a safety net for any that still throw.
|
||||
|
||||
- [ ] **3.8 Handle `throw` inside `try/catch`** (`src/HIR/BuildHIR.ts`, line ~284)
|
||||
- Currently throws Todo
|
||||
- Instead: record the error, and represent the `throw` as a terminal that ends the block (the existing `throw` terminal type may already handle this, or we can use `UnsupportedNode`)
|
||||
- [x] **3.8 Handle `throw` inside `try/catch`** (`src/HIR/BuildHIR.ts`, line ~284)
|
||||
- Already handled: records error via `builder.errors.push()` and continues
|
||||
|
||||
- [ ] **3.9 Handle `for` loops with missing test or expression init** (`src/HIR/BuildHIR.ts`, lines ~559, ~632)
|
||||
- Record the error and construct a best-effort loop HIR (e.g., for `for(;;)`, use `true` as the test expression)
|
||||
- [x] **3.9 Handle `for` loops with missing test or expression init** (`src/HIR/BuildHIR.ts`, lines ~559, ~632)
|
||||
- For `for(;;)` (missing test): emit `true` as the test expression and add a branch terminal
|
||||
- For empty init (`for (; ...)`): add a placeholder instruction to avoid invariant about empty blocks
|
||||
- For expression init (`for (expr; ...)`): record error and lower the expression as best-effort
|
||||
- Changed `'unsupported'` terminal to `'goto'` terminal for non-variable init to maintain valid CFG structure
|
||||
|
||||
- [ ] **3.10 Handle nested function lowering failures** (`src/HIR/BuildHIR.ts`, `lowerFunction` at line ~3504)
|
||||
- Currently calls `lower()` recursively and merges errors if it fails (`builder.errors.merge(functionErrors)`)
|
||||
- With the new approach, the nested `lower()` always returns an HIR, but errors are recorded on the shared environment
|
||||
- Ensure the parent function continues lowering even if a nested function had errors
|
||||
- [x] **3.10 Handle nested function lowering failures** (`src/HIR/BuildHIR.ts`, `lowerFunction` at line ~3504)
|
||||
- `lowerFunction()` now always returns `LoweredFunction` since `lower()` always returns `HIRFunction`
|
||||
- Errors from nested functions are recorded on the shared environment
|
||||
- Removed the `null` return case and the corresponding `UnsupportedNode` fallback in callers
|
||||
|
||||
- [x] **3.11 Handle unreachable functions in `build()`** (`src/HIR/HIRBuilder.ts`, `build()`)
|
||||
- Changed `CompilerError.throwTodo()` for unreachable code with hoisted declarations to `this.errors.push()` to allow HIR construction to complete
|
||||
|
||||
- [x] **3.12 Handle duplicate fbt tags** (`src/HIR/BuildHIR.ts`, line ~2279)
|
||||
- Changed `CompilerError.throwDiagnostic()` to `builder.errors.pushDiagnostic()` to record instead of throw
|
||||
|
||||
### Phase 4: Update Validation Passes
|
||||
|
||||
@@ -324,4 +324,7 @@ Walk through `runWithEnvironment` and wrap each pass call site. This is the inte
|
||||
* **Lint-only passes (Pattern B: `env.logErrors()`) should not use `tryRecord()`/`recordError()`** because those errors are intentionally non-blocking. They are reported via the logger only and should not cause the pipeline to return `Err`. The `logErrors` pattern was kept for `validateNoDerivedComputationsInEffects_exp`, `validateNoSetStateInEffects`, `validateNoJSXInTryStatement`, and `validateStaticComponents`.
|
||||
* **Inference passes that return `Result` with validation errors** (`inferMutationAliasingEffects`, `inferMutationAliasingRanges`) were changed to record errors via `env.recordErrors()` instead of throwing, allowing subsequent passes to proceed.
|
||||
* **Value-producing passes** (`memoizeFbtAndMacroOperandsInSameScope`, `renameVariables`, `buildReactiveFunction`) need safe default values when wrapped in `tryRecord()` since the callback can't return values. We initialize with empty defaults (e.g., `new Set()`) before the `tryRecord()` call.
|
||||
* **Phase 3 (BuildHIR) revealed that most error sites already used `builder.errors.push()` for accumulation.** The existing lowering code was designed to accumulate errors rather than throw. The main changes were: (1) changing `lower()` return type from `Result` to `HIRFunction`, (2) recording builder errors on env, (3) adding a try/catch around body lowering to catch thrown CompilerErrors from sub-calls like `resolveBinding()`, (4) treating `var` as `let` instead of skipping declarations, and (5) fixing ForStatement init/test handling to produce valid CFG structure.
|
||||
* **Partial HIR can trigger downstream invariants.** When lowering skips or partially handles constructs (e.g., unreachable hoisted functions, `var` declarations before the fix), downstream passes like `InferMutationAliasingEffects` may encounter uninitialized identifiers and throw invariants. This is acceptable since the function still correctly bails out of compilation, but error messages may be less specific. The fix for `var` (treating as `let`) demonstrates how to avoid this: continue lowering with a best-effort representation rather than skipping entirely.
|
||||
* **Errors accumulated on `env` are lost when an invariant propagates out of the pipeline.** Since invariant CompilerErrors always re-throw through `tryRecord()`, they exit the pipeline as exceptions. The caller only sees the invariant error, not any errors previously recorded on `env`. This is a design limitation that could be addressed by aggregating env errors with caught exceptions in `tryCompileFunction()`.
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ function runWithEnvironment(
|
||||
const log = (value: CompilerPipelineValue): void => {
|
||||
env.logger?.debugLogIRs?.(value);
|
||||
};
|
||||
const hir = lower(func, env).unwrap();
|
||||
const hir = lower(func, env);
|
||||
log({kind: 'hir', name: 'HIR', value: hir});
|
||||
|
||||
env.tryRecord(() => {
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
CompilerSuggestionOperation,
|
||||
ErrorCategory,
|
||||
} from '../CompilerError';
|
||||
import {Err, Ok, Result} from '../Utils/Result';
|
||||
import {assertExhaustive, hasNode} from '../Utils/utils';
|
||||
import {Environment} from './Environment';
|
||||
import {
|
||||
@@ -75,7 +74,7 @@ export function lower(
|
||||
// Bindings captured from the outer function, in case lower() is called recursively (for lambdas)
|
||||
bindings: Bindings | null = null,
|
||||
capturedRefs: Map<t.Identifier, SourceLocation> = new Map(),
|
||||
): Result<HIRFunction, CompilerError> {
|
||||
): HIRFunction {
|
||||
const builder = new HIRBuilder(env, {
|
||||
bindings,
|
||||
context: capturedRefs,
|
||||
@@ -186,32 +185,51 @@ export function lower(
|
||||
|
||||
let directives: Array<string> = [];
|
||||
const body = func.get('body');
|
||||
if (body.isExpression()) {
|
||||
const fallthrough = builder.reserve('block');
|
||||
const terminal: ReturnTerminal = {
|
||||
kind: 'return',
|
||||
returnVariant: 'Implicit',
|
||||
loc: GeneratedSource,
|
||||
value: lowerExpressionToTemporary(builder, body),
|
||||
id: makeInstructionId(0),
|
||||
effects: null,
|
||||
};
|
||||
builder.terminateWithContinuation(terminal, fallthrough);
|
||||
} else if (body.isBlockStatement()) {
|
||||
lowerStatement(builder, body);
|
||||
directives = body.get('directives').map(d => d.node.value.value);
|
||||
} else {
|
||||
builder.errors.pushDiagnostic(
|
||||
CompilerDiagnostic.create({
|
||||
category: ErrorCategory.Syntax,
|
||||
reason: `Unexpected function body kind`,
|
||||
description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
|
||||
}).withDetails({
|
||||
kind: 'error',
|
||||
loc: body.node.loc ?? null,
|
||||
message: 'Expected a block statement or expression',
|
||||
}),
|
||||
);
|
||||
try {
|
||||
if (body.isExpression()) {
|
||||
const fallthrough = builder.reserve('block');
|
||||
const terminal: ReturnTerminal = {
|
||||
kind: 'return',
|
||||
returnVariant: 'Implicit',
|
||||
loc: GeneratedSource,
|
||||
value: lowerExpressionToTemporary(builder, body),
|
||||
id: makeInstructionId(0),
|
||||
effects: null,
|
||||
};
|
||||
builder.terminateWithContinuation(terminal, fallthrough);
|
||||
} else if (body.isBlockStatement()) {
|
||||
lowerStatement(builder, body);
|
||||
directives = body.get('directives').map(d => d.node.value.value);
|
||||
} else {
|
||||
builder.errors.pushDiagnostic(
|
||||
CompilerDiagnostic.create({
|
||||
category: ErrorCategory.Syntax,
|
||||
reason: `Unexpected function body kind`,
|
||||
description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
|
||||
}).withDetails({
|
||||
kind: 'error',
|
||||
loc: body.node.loc ?? null,
|
||||
message: 'Expected a block statement or expression',
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof CompilerError) {
|
||||
// Re-throw invariant errors immediately
|
||||
for (const detail of err.details) {
|
||||
if (
|
||||
(detail instanceof CompilerDiagnostic
|
||||
? detail.category
|
||||
: detail.category) === ErrorCategory.Invariant
|
||||
) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
// Record non-invariant errors and continue to produce partial HIR
|
||||
builder.errors.merge(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
let validatedId: HIRFunction['id'] = null;
|
||||
@@ -224,10 +242,6 @@ export function lower(
|
||||
}
|
||||
}
|
||||
|
||||
if (builder.errors.hasAnyErrors()) {
|
||||
return Err(builder.errors);
|
||||
}
|
||||
|
||||
builder.terminate(
|
||||
{
|
||||
kind: 'return',
|
||||
@@ -244,23 +258,29 @@ export function lower(
|
||||
null,
|
||||
);
|
||||
|
||||
return Ok({
|
||||
const hirBody = builder.build();
|
||||
|
||||
// Record all accumulated errors (including any from build()) on env
|
||||
if (builder.errors.hasAnyErrors()) {
|
||||
env.recordErrors(builder.errors);
|
||||
}
|
||||
|
||||
return {
|
||||
id: validatedId,
|
||||
nameHint: null,
|
||||
params,
|
||||
fnType: bindings == null ? env.fnType : 'Other',
|
||||
returnTypeAnnotation: null, // TODO: extract the actual return type node if present
|
||||
returns: createTemporaryPlace(env, func.node.loc ?? GeneratedSource),
|
||||
body: builder.build(),
|
||||
body: hirBody,
|
||||
context,
|
||||
generator: func.node.generator === true,
|
||||
async: func.node.async === true,
|
||||
loc: func.node.loc ?? GeneratedSource,
|
||||
env,
|
||||
effects: null,
|
||||
aliasingEffects: null,
|
||||
directives,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Helper to lower a statement
|
||||
@@ -555,6 +575,22 @@ function lowerStatement(
|
||||
|
||||
const initBlock = builder.enter('loop', _blockId => {
|
||||
const init = stmt.get('init');
|
||||
if (init.node == null) {
|
||||
// No init expression (e.g., `for (; ...)`), add a placeholder to avoid
|
||||
// invariant about empty blocks
|
||||
lowerValueToTemporary(builder, {
|
||||
kind: 'Primitive',
|
||||
value: undefined,
|
||||
loc: stmt.node.loc ?? GeneratedSource,
|
||||
});
|
||||
return {
|
||||
kind: 'goto',
|
||||
block: testBlock.id,
|
||||
variant: GotoVariant.Break,
|
||||
id: makeInstructionId(0),
|
||||
loc: stmt.node.loc ?? GeneratedSource,
|
||||
};
|
||||
}
|
||||
if (!init.isVariableDeclaration()) {
|
||||
builder.errors.push({
|
||||
reason:
|
||||
@@ -563,8 +599,14 @@ function lowerStatement(
|
||||
loc: stmt.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
// Lower the init expression as best-effort and continue
|
||||
if (init.isExpression()) {
|
||||
lowerExpressionToTemporary(builder, init as NodePath<t.Expression>);
|
||||
}
|
||||
return {
|
||||
kind: 'unsupported',
|
||||
kind: 'goto',
|
||||
block: testBlock.id,
|
||||
variant: GotoVariant.Break,
|
||||
id: makeInstructionId(0),
|
||||
loc: init.node?.loc ?? GeneratedSource,
|
||||
};
|
||||
@@ -635,6 +677,23 @@ function lowerStatement(
|
||||
loc: stmt.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
// Treat `for(;;)` as `while(true)` to keep the builder state consistent
|
||||
builder.terminateWithContinuation(
|
||||
{
|
||||
kind: 'branch',
|
||||
test: lowerValueToTemporary(builder, {
|
||||
kind: 'Primitive',
|
||||
value: true,
|
||||
loc: stmt.node.loc ?? GeneratedSource,
|
||||
}),
|
||||
consequent: bodyBlock,
|
||||
alternate: continuationBlock.id,
|
||||
fallthrough: continuationBlock.id,
|
||||
id: makeInstructionId(0),
|
||||
loc: stmt.node.loc ?? GeneratedSource,
|
||||
},
|
||||
continuationBlock,
|
||||
);
|
||||
} else {
|
||||
builder.terminateWithContinuation(
|
||||
{
|
||||
@@ -858,10 +917,12 @@ function lowerStatement(
|
||||
loc: stmt.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
return;
|
||||
// Treat `var` as `let` so references to the variable don't break
|
||||
}
|
||||
const kind =
|
||||
nodeKind === 'let' ? InstructionKind.Let : InstructionKind.Const;
|
||||
nodeKind === 'let' || nodeKind === 'var'
|
||||
? InstructionKind.Let
|
||||
: InstructionKind.Const;
|
||||
for (const declaration of stmt.get('declarations')) {
|
||||
const id = declaration.get('id');
|
||||
const init = declaration.get('init');
|
||||
@@ -1494,9 +1555,6 @@ function lowerObjectMethod(
|
||||
): InstructionValue {
|
||||
const loc = property.node.loc ?? GeneratedSource;
|
||||
const loweredFunc = lowerFunction(builder, property);
|
||||
if (!loweredFunc) {
|
||||
return {kind: 'UnsupportedNode', node: property.node, loc: loc};
|
||||
}
|
||||
|
||||
return {
|
||||
kind: 'ObjectMethod',
|
||||
@@ -2276,18 +2334,20 @@ function lowerExpression(
|
||||
});
|
||||
for (const [name, locations] of Object.entries(fbtLocations)) {
|
||||
if (locations.length > 1) {
|
||||
CompilerError.throwDiagnostic({
|
||||
category: ErrorCategory.Todo,
|
||||
reason: 'Support duplicate fbt tags',
|
||||
description: `Support \`<${tagName}>\` tags with multiple \`<${tagName}:${name}>\` values`,
|
||||
details: locations.map(loc => {
|
||||
return {
|
||||
kind: 'error',
|
||||
message: `Multiple \`<${tagName}:${name}>\` tags found`,
|
||||
loc,
|
||||
};
|
||||
builder.errors.pushDiagnostic(
|
||||
new CompilerDiagnostic({
|
||||
category: ErrorCategory.Todo,
|
||||
reason: 'Support duplicate fbt tags',
|
||||
description: `Support \`<${tagName}>\` tags with multiple \`<${tagName}:${name}>\` values`,
|
||||
details: locations.map(loc => {
|
||||
return {
|
||||
kind: 'error' as const,
|
||||
message: `Multiple \`<${tagName}:${name}>\` tags found`,
|
||||
loc,
|
||||
};
|
||||
}),
|
||||
}),
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3468,9 +3528,6 @@ function lowerFunctionToValue(
|
||||
const exprNode = expr.node;
|
||||
const exprLoc = exprNode.loc ?? GeneratedSource;
|
||||
const loweredFunc = lowerFunction(builder, expr);
|
||||
if (!loweredFunc) {
|
||||
return {kind: 'UnsupportedNode', node: exprNode, loc: exprLoc};
|
||||
}
|
||||
return {
|
||||
kind: 'FunctionExpression',
|
||||
name: loweredFunc.func.id,
|
||||
@@ -3489,7 +3546,7 @@ function lowerFunction(
|
||||
| t.FunctionDeclaration
|
||||
| t.ObjectMethod
|
||||
>,
|
||||
): LoweredFunction | null {
|
||||
): LoweredFunction {
|
||||
const componentScope: Scope = builder.environment.parentFunction.scope;
|
||||
const capturedContext = gatherCapturedContext(expr, componentScope);
|
||||
|
||||
@@ -3501,19 +3558,12 @@ function lowerFunction(
|
||||
* This isn't a problem in practice because use Babel's scope analysis to
|
||||
* identify the correct references.
|
||||
*/
|
||||
const lowering = lower(
|
||||
const loweredFunc = lower(
|
||||
expr,
|
||||
builder.environment,
|
||||
builder.bindings,
|
||||
new Map([...builder.context, ...capturedContext]),
|
||||
);
|
||||
let loweredFunc: HIRFunction;
|
||||
if (lowering.isErr()) {
|
||||
const functionErrors = lowering.unwrapErr();
|
||||
builder.errors.merge(functionErrors);
|
||||
return null;
|
||||
}
|
||||
loweredFunc = lowering.unwrap();
|
||||
return {
|
||||
func: loweredFunc,
|
||||
};
|
||||
|
||||
@@ -381,11 +381,12 @@ export default class HIRBuilder {
|
||||
instr => instr.value.kind === 'FunctionExpression',
|
||||
)
|
||||
) {
|
||||
CompilerError.throwTodo({
|
||||
this.errors.push({
|
||||
reason: `Support functions with unreachable code that may contain hoisted declarations`,
|
||||
loc: block.instructions[0]?.loc ?? block.terminal.loc,
|
||||
description: null,
|
||||
suggestions: null,
|
||||
category: ErrorCategory.Todo,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,18 +24,9 @@ function useThing(fn) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Compilation Skipped: `this` is not supported syntax
|
||||
Invariant: [HIRBuilder] Unexpected null block
|
||||
|
||||
React Compiler does not support compiling functions that use `this`.
|
||||
|
||||
error.reserved-words.ts:8:28
|
||||
6 |
|
||||
7 | if (ref.current === null) {
|
||||
> 8 | ref.current = function (this: unknown, ...args) {
|
||||
| ^^^^^^^^^^^^^ `this` was used here
|
||||
9 | return fnRef.current.call(this, ...args);
|
||||
10 | };
|
||||
11 | }
|
||||
expected block 0 to exist.
|
||||
```
|
||||
|
||||
|
||||
@@ -17,16 +17,17 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Todo: (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern
|
||||
Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
|
||||
|
||||
error._todo.computed-lval-in-destructure.ts:3:9
|
||||
1 | function Component(props) {
|
||||
2 | const computedKey = props.key;
|
||||
> 3 | const {[computedKey]: x} = props.val;
|
||||
| ^^^^^^^^^^^^^^^^ (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern
|
||||
<unknown> x$8.
|
||||
|
||||
error._todo.computed-lval-in-destructure.ts:5:9
|
||||
3 | const {[computedKey]: x} = props.val;
|
||||
4 |
|
||||
5 | return x;
|
||||
> 5 | return x;
|
||||
| ^ this is uninitialized
|
||||
6 | }
|
||||
7 |
|
||||
```
|
||||
|
||||
|
||||
@@ -18,15 +18,18 @@ function Component() {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Todo: Support functions with unreachable code that may contain hoisted declarations
|
||||
Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
|
||||
|
||||
error.todo-hoisted-function-in-unreachable-code.ts:6:2
|
||||
<unknown> Foo$0.
|
||||
|
||||
error.todo-hoisted-function-in-unreachable-code.ts:3:10
|
||||
1 | // @compilationMode:"infer"
|
||||
2 | function Component() {
|
||||
> 3 | return <Foo />;
|
||||
| ^^^ this is uninitialized
|
||||
4 |
|
||||
5 | // This is unreachable from a control-flow perspective, but it gets hoisted
|
||||
> 6 | function Foo() {}
|
||||
| ^^^^^^^^^^^^^^^^^ Support functions with unreachable code that may contain hoisted declarations
|
||||
7 | }
|
||||
8 |
|
||||
6 | function Foo() {}
|
||||
```
|
||||
|
||||
|
||||
@@ -79,43 +79,11 @@ let moduleLocal = false;
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 10 errors:
|
||||
Found 1 error:
|
||||
|
||||
Todo: (BuildHIR::lowerStatement) Handle var kinds in VariableDeclaration
|
||||
Invariant: Expected a variable declaration
|
||||
|
||||
error.todo-kitchensink.ts:3:2
|
||||
1 | function foo([a, b], {c, d, e = 'e'}, f = 'f', ...args) {
|
||||
2 | let i = 0;
|
||||
> 3 | var x = [];
|
||||
| ^^^^^^^^^^^ (BuildHIR::lowerStatement) Handle var kinds in VariableDeclaration
|
||||
4 |
|
||||
5 | class Bar {
|
||||
6 | #secretSauce = 42;
|
||||
|
||||
Compilation Skipped: Inline `class` declarations are not supported
|
||||
|
||||
Move class declarations outside of components/hooks.
|
||||
|
||||
error.todo-kitchensink.ts:5:2
|
||||
3 | var x = [];
|
||||
4 |
|
||||
> 5 | class Bar {
|
||||
| ^^^^^^^^^^^
|
||||
> 6 | #secretSauce = 42;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
> 7 | constructor() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
> 8 | console.log(this.#secretSauce);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
> 9 | }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
> 10 | }
|
||||
| ^^^^ Inline `class` declarations are not supported
|
||||
11 |
|
||||
12 | const g = {b() {}, c: () => {}};
|
||||
13 | const {z, aa = 'aa'} = useCustom();
|
||||
|
||||
Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
|
||||
Got ExpressionStatement.
|
||||
|
||||
error.todo-kitchensink.ts:20:2
|
||||
18 | const j = function bar([quz, qux], ...args) {};
|
||||
@@ -125,103 +93,10 @@ error.todo-kitchensink.ts:20:2
|
||||
> 21 | x.push(i);
|
||||
| ^^^^^^^^^^^^^^
|
||||
> 22 | }
|
||||
| ^^^^ (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
|
||||
| ^^^^ Expected a variable declaration
|
||||
23 | for (; i < 3; ) {
|
||||
24 | break;
|
||||
25 | }
|
||||
|
||||
Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
|
||||
|
||||
error.todo-kitchensink.ts:23:2
|
||||
21 | x.push(i);
|
||||
22 | }
|
||||
> 23 | for (; i < 3; ) {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 24 | break;
|
||||
| ^^^^^^^^^^
|
||||
> 25 | }
|
||||
| ^^^^ (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
|
||||
26 | for (;;) {
|
||||
27 | break;
|
||||
28 | }
|
||||
|
||||
Todo: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
|
||||
|
||||
error.todo-kitchensink.ts:26:2
|
||||
24 | break;
|
||||
25 | }
|
||||
> 26 | for (;;) {
|
||||
| ^^^^^^^^^^
|
||||
> 27 | break;
|
||||
| ^^^^^^^^^^
|
||||
> 28 | }
|
||||
| ^^^^ (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
|
||||
29 |
|
||||
30 | graphql`
|
||||
31 | ${g}
|
||||
|
||||
Todo: (BuildHIR::lowerStatement) Handle empty test in ForStatement
|
||||
|
||||
error.todo-kitchensink.ts:26:2
|
||||
24 | break;
|
||||
25 | }
|
||||
> 26 | for (;;) {
|
||||
| ^^^^^^^^^^
|
||||
> 27 | break;
|
||||
| ^^^^^^^^^^
|
||||
> 28 | }
|
||||
| ^^^^ (BuildHIR::lowerStatement) Handle empty test in ForStatement
|
||||
29 |
|
||||
30 | graphql`
|
||||
31 | ${g}
|
||||
|
||||
Todo: (BuildHIR::lowerExpression) Handle tagged template with interpolations
|
||||
|
||||
error.todo-kitchensink.ts:30:2
|
||||
28 | }
|
||||
29 |
|
||||
> 30 | graphql`
|
||||
| ^^^^^^^^
|
||||
> 31 | ${g}
|
||||
| ^^^^^^^^
|
||||
> 32 | `;
|
||||
| ^^^^ (BuildHIR::lowerExpression) Handle tagged template with interpolations
|
||||
33 |
|
||||
34 | graphql`\\t\n`;
|
||||
35 |
|
||||
|
||||
Todo: (BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value
|
||||
|
||||
error.todo-kitchensink.ts:34:2
|
||||
32 | `;
|
||||
33 |
|
||||
> 34 | graphql`\\t\n`;
|
||||
| ^^^^^^^^^^^^^^ (BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value
|
||||
35 |
|
||||
36 | for (c of [1, 2]) {
|
||||
37 | }
|
||||
|
||||
Todo: (BuildHIR::node.lowerReorderableExpression) Expression type `MemberExpression` cannot be safely reordered
|
||||
|
||||
error.todo-kitchensink.ts:57:9
|
||||
55 | case foo(): {
|
||||
56 | }
|
||||
> 57 | case x.y: {
|
||||
| ^^^ (BuildHIR::node.lowerReorderableExpression) Expression type `MemberExpression` cannot be safely reordered
|
||||
58 | }
|
||||
59 | default: {
|
||||
60 | }
|
||||
|
||||
Todo: (BuildHIR::node.lowerReorderableExpression) Expression type `BinaryExpression` cannot be safely reordered
|
||||
|
||||
error.todo-kitchensink.ts:53:9
|
||||
51 |
|
||||
52 | switch (i) {
|
||||
> 53 | case 1 + 1: {
|
||||
| ^^^^^ (BuildHIR::node.lowerReorderableExpression) Expression type `BinaryExpression` cannot be safely reordered
|
||||
54 | }
|
||||
55 | case foo(): {
|
||||
56 | }
|
||||
```
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ function component(a, b) {
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 1 error:
|
||||
Found 2 errors:
|
||||
|
||||
Todo: (BuildHIR::lowerExpression) Handle YieldExpression expressions
|
||||
|
||||
@@ -30,6 +30,23 @@ error.useMemo-callback-generator.ts:6:4
|
||||
7 | }, []);
|
||||
8 | return x;
|
||||
9 | }
|
||||
|
||||
Error: useMemo() callbacks may not be async or generator functions
|
||||
|
||||
useMemo() callbacks are called once and must synchronously return a value.
|
||||
|
||||
error.useMemo-callback-generator.ts:5:18
|
||||
3 | // useful for now, but adding this test in case we do
|
||||
4 | // add support for generators in the future.
|
||||
> 5 | let x = useMemo(function* () {
|
||||
| ^^^^^^^^^^^^^^
|
||||
> 6 | yield a;
|
||||
| ^^^^^^^^^^^^
|
||||
> 7 | }, []);
|
||||
| ^^^^ Async and generator functions are not supported
|
||||
8 | return x;
|
||||
9 | }
|
||||
10 |
|
||||
```
|
||||
|
||||
|
||||
@@ -23,16 +23,18 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Todo: (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern
|
||||
Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized
|
||||
|
||||
todo.error.object-pattern-computed-key.ts:5:9
|
||||
3 | const SCALE = 2;
|
||||
<unknown> value$3.
|
||||
|
||||
todo.error.object-pattern-computed-key.ts:6:9
|
||||
4 | function Component(props) {
|
||||
> 5 | const {[props.name]: value} = props;
|
||||
| ^^^^^^^^^^^^^^^^^^^ (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern
|
||||
6 | return value;
|
||||
5 | const {[props.name]: value} = props;
|
||||
> 6 | return value;
|
||||
| ^^^^^ this is uninitialized
|
||||
7 | }
|
||||
8 |
|
||||
9 | export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user