mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
## Proper Detection of Out-of-order Functions
The no-use-before-define rule from ESLint has a strange behavior in which it
treats variables differently than functions:
```javascript
function foo() {
return bar(X);
}
const X = null;
function bar(x) {}
```
By default, `bar(x)` has two errors: one because X is used before defined, and
once because `bar` is used before defined. The rule has an option `{variables:
false}` which only enables validation when the variable is from the same "scope"
as the reference, the net result of which is it means it doesn't report spurious
errors such as X being undefined. There is _also_ a `{functions: false}` option,
but for some reason that doesn't work the same way, it just turns off all
validation of references that came from functions. So enabling that option would
suppress the (spurious) error on invoking `bar()` above, but causes the rule to
miss invalid code such as:
```
function foo() {
return bar();
function bar() {}
}
```
This PR adds a fork of the rule that makes `{functions: false}` behave similarly
to `{variables: false}`, which should help avoid some of the spurious errors i
saw internally. The rule is exported from Forget itself, which will make it
easier to consume internally, in tests, and in the playground.
## Targeting the validation to Forget functions
Even with the above, there are still some false positives coming from code such
as:
```javascript
const x = foo();
function foo() {}
```
This PR changes codegen to ensure that the output of a function _always_ has the
body starting with 'use forget'. The ESLint rule then only looks at function
declarations/expressions whose body starts with that expression. The new unit
test confirms that the validation finds invalid reorderings even on functions
that weren't explicitly tagged as 'use forget'.
69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import { NodePath } from "@babel/traverse";
|
|
import * as t from "@babel/types";
|
|
import * as BE from "./BackEnd";
|
|
import { CompilerContext } from "./CompilerContext";
|
|
import { CompilerOptions } from "./CompilerOptions";
|
|
import * as ME from "./MiddleEnd";
|
|
import { PassManager } from "./PassManager";
|
|
import * as Validation from "./Validation";
|
|
|
|
/**
|
|
* Compiler Driver
|
|
*
|
|
* Owns {@link CompilerContext} and source program.
|
|
*/
|
|
export interface CompilerDriver {
|
|
context: CompilerContext;
|
|
program: NodePath<t.Program>;
|
|
compile(): void;
|
|
}
|
|
|
|
export function createCompilerDriver(
|
|
options: CompilerOptions,
|
|
program: NodePath<t.Program>
|
|
): CompilerDriver {
|
|
const context = new CompilerContext(options, program);
|
|
|
|
return {
|
|
context,
|
|
program,
|
|
compile() {
|
|
const passManager = new PassManager(program, context);
|
|
|
|
// Syntax Analysis and IR Generation.
|
|
passManager.addPass(ME.ReactFuncsInfer);
|
|
passManager.addPass(ME.ParamAnalysis);
|
|
passManager.addPass(ME.BodyAnalysis);
|
|
passManager.addPass(ME.SketchyCodeCheck);
|
|
passManager.addPass(ME.RefKindInfer);
|
|
passManager.addPass(ME.DumpIR);
|
|
passManager.addPass(ME.IRCheck);
|
|
passManager.addPass(ME.DumpCFG);
|
|
|
|
// Dependency Analysis via DepGraph.
|
|
passManager.addPass(ME.DepGraphAnalysis);
|
|
|
|
// LIR Generation.
|
|
passManager.addPass(BE.LIRGen);
|
|
passManager.addPass(BE.MemoCacheAlloc);
|
|
passManager.addPass(BE.DumpLIR);
|
|
passManager.addPass(BE.SanityCheck);
|
|
|
|
// JS Generation.
|
|
passManager.addPass(BE.JSGen);
|
|
|
|
// Optionally sanity-check the transformed output
|
|
passManager.addPass(Validation.PostCodegenValidator);
|
|
|
|
passManager.runAll();
|
|
},
|
|
};
|
|
}
|