Files
react/compiler/forget/src/CompilerDriver.ts
T
Joseph Savona 515c33d2a6 Custom version of no-use-before-define rule
## 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'.
2022-10-27 16:29:09 -07:00

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();
},
};
}