Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f53c391fb |
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,12 @@
|
|||||||
|
|
||||||
import {Binding, NodePath} from '@babel/traverse';
|
import {Binding, NodePath} from '@babel/traverse';
|
||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import {CompilerError, ErrorCategory} from '../CompilerError';
|
import {
|
||||||
|
CompilerError,
|
||||||
|
CompilerDiagnostic,
|
||||||
|
CompilerErrorDetail,
|
||||||
|
ErrorCategory,
|
||||||
|
} from '../CompilerError';
|
||||||
import {Environment} from './Environment';
|
import {Environment} from './Environment';
|
||||||
import {
|
import {
|
||||||
BasicBlock,
|
BasicBlock,
|
||||||
@@ -110,7 +115,6 @@ export default class HIRBuilder {
|
|||||||
#bindings: Bindings;
|
#bindings: Bindings;
|
||||||
#env: Environment;
|
#env: Environment;
|
||||||
#exceptionHandlerStack: Array<BlockId> = [];
|
#exceptionHandlerStack: Array<BlockId> = [];
|
||||||
errors: CompilerError = new CompilerError();
|
|
||||||
/**
|
/**
|
||||||
* Traversal context: counts the number of `fbt` tag parents
|
* Traversal context: counts the number of `fbt` tag parents
|
||||||
* of the current babel node.
|
* of the current babel node.
|
||||||
@@ -148,6 +152,10 @@ export default class HIRBuilder {
|
|||||||
this.#current = newBlock(this.#entry, options?.entryBlockKind ?? 'block');
|
this.#current = newBlock(this.#entry, options?.entryBlockKind ?? 'block');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recordError(error: CompilerDiagnostic | CompilerErrorDetail): void {
|
||||||
|
this.#env.recordError(error);
|
||||||
|
}
|
||||||
|
|
||||||
currentBlockKind(): BlockKind {
|
currentBlockKind(): BlockKind {
|
||||||
return this.#current.kind;
|
return this.#current.kind;
|
||||||
}
|
}
|
||||||
@@ -308,24 +316,28 @@ export default class HIRBuilder {
|
|||||||
|
|
||||||
resolveBinding(node: t.Identifier): Identifier {
|
resolveBinding(node: t.Identifier): Identifier {
|
||||||
if (node.name === 'fbt') {
|
if (node.name === 'fbt') {
|
||||||
this.errors.push({
|
this.recordError(
|
||||||
category: ErrorCategory.Todo,
|
new CompilerErrorDetail({
|
||||||
reason: 'Support local variables named `fbt`',
|
category: ErrorCategory.Todo,
|
||||||
description:
|
reason: 'Support local variables named `fbt`',
|
||||||
'Local variables named `fbt` may conflict with the fbt plugin and are not yet supported',
|
description:
|
||||||
loc: node.loc ?? GeneratedSource,
|
'Local variables named `fbt` may conflict with the fbt plugin and are not yet supported',
|
||||||
suggestions: null,
|
loc: node.loc ?? GeneratedSource,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (node.name === 'this') {
|
if (node.name === 'this') {
|
||||||
this.errors.push({
|
this.recordError(
|
||||||
category: ErrorCategory.UnsupportedSyntax,
|
new CompilerErrorDetail({
|
||||||
reason: '`this` is not supported syntax',
|
category: ErrorCategory.UnsupportedSyntax,
|
||||||
description:
|
reason: '`this` is not supported syntax',
|
||||||
'React Compiler does not support compiling functions that use `this`',
|
description:
|
||||||
loc: node.loc ?? GeneratedSource,
|
'React Compiler does not support compiling functions that use `this`',
|
||||||
suggestions: null,
|
loc: node.loc ?? GeneratedSource,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const originalName = node.name;
|
const originalName = node.name;
|
||||||
let name = originalName;
|
let name = originalName;
|
||||||
@@ -371,13 +383,15 @@ export default class HIRBuilder {
|
|||||||
instr => instr.value.kind === 'FunctionExpression',
|
instr => instr.value.kind === 'FunctionExpression',
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.errors.push({
|
this.recordError(
|
||||||
reason: `Support functions with unreachable code that may contain hoisted declarations`,
|
new CompilerErrorDetail({
|
||||||
loc: block.instructions[0]?.loc ?? block.terminal.loc,
|
reason: `Support functions with unreachable code that may contain hoisted declarations`,
|
||||||
description: null,
|
loc: block.instructions[0]?.loc ?? block.terminal.loc,
|
||||||
suggestions: null,
|
description: null,
|
||||||
category: ErrorCategory.Todo,
|
suggestions: null,
|
||||||
});
|
category: ErrorCategory.Todo,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ir.blocks = rpoBlocks;
|
ir.blocks = rpoBlocks;
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ function extractManualMemoizationArgs(
|
|||||||
instr: TInstruction<CallExpression> | TInstruction<MethodCall>,
|
instr: TInstruction<CallExpression> | TInstruction<MethodCall>,
|
||||||
kind: 'useCallback' | 'useMemo',
|
kind: 'useCallback' | 'useMemo',
|
||||||
sidemap: IdentifierSidemap,
|
sidemap: IdentifierSidemap,
|
||||||
errors: CompilerError,
|
env: Environment,
|
||||||
): {
|
): {
|
||||||
fnPlace: Place;
|
fnPlace: Place;
|
||||||
depsList: Array<ManualMemoDependency> | null;
|
depsList: Array<ManualMemoDependency> | null;
|
||||||
@@ -303,7 +303,7 @@ function extractManualMemoizationArgs(
|
|||||||
Place | SpreadPattern | undefined
|
Place | SpreadPattern | undefined
|
||||||
>;
|
>;
|
||||||
if (fnPlace == null || fnPlace.kind !== 'Identifier') {
|
if (fnPlace == null || fnPlace.kind !== 'Identifier') {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: `Expected a callback function to be passed to ${kind}`,
|
reason: `Expected a callback function to be passed to ${kind}`,
|
||||||
@@ -335,7 +335,7 @@ function extractManualMemoizationArgs(
|
|||||||
? sidemap.maybeDepsLists.get(depsListPlace.identifier.id)
|
? sidemap.maybeDepsLists.get(depsListPlace.identifier.id)
|
||||||
: null;
|
: null;
|
||||||
if (maybeDepsList == null) {
|
if (maybeDepsList == null) {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: `Expected the dependency list for ${kind} to be an array literal`,
|
reason: `Expected the dependency list for ${kind} to be an array literal`,
|
||||||
@@ -354,7 +354,7 @@ function extractManualMemoizationArgs(
|
|||||||
for (const dep of maybeDepsList.deps) {
|
for (const dep of maybeDepsList.deps) {
|
||||||
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
|
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
|
||||||
if (maybeDep == null) {
|
if (maybeDep == null) {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
||||||
@@ -389,7 +389,6 @@ function extractManualMemoizationArgs(
|
|||||||
* is only used for memoizing values and not for running arbitrary side effects.
|
* is only used for memoizing values and not for running arbitrary side effects.
|
||||||
*/
|
*/
|
||||||
export function dropManualMemoization(func: HIRFunction): void {
|
export function dropManualMemoization(func: HIRFunction): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
const isValidationEnabled =
|
const isValidationEnabled =
|
||||||
func.env.config.validatePreserveExistingMemoizationGuarantees ||
|
func.env.config.validatePreserveExistingMemoizationGuarantees ||
|
||||||
func.env.config.validateNoSetStateInRender ||
|
func.env.config.validateNoSetStateInRender ||
|
||||||
@@ -436,7 +435,7 @@ export function dropManualMemoization(func: HIRFunction): void {
|
|||||||
instr as TInstruction<CallExpression> | TInstruction<MethodCall>,
|
instr as TInstruction<CallExpression> | TInstruction<MethodCall>,
|
||||||
manualMemo.kind,
|
manualMemo.kind,
|
||||||
sidemap,
|
sidemap,
|
||||||
errors,
|
func.env,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (memoDetails == null) {
|
if (memoDetails == null) {
|
||||||
@@ -464,7 +463,7 @@ export function dropManualMemoization(func: HIRFunction): void {
|
|||||||
* is rare and likely sketchy.
|
* is rare and likely sketchy.
|
||||||
*/
|
*/
|
||||||
if (!sidemap.functions.has(fnPlace.identifier.id)) {
|
if (!sidemap.functions.has(fnPlace.identifier.id)) {
|
||||||
errors.pushDiagnostic(
|
func.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: `Expected the first argument to be an inline function expression`,
|
reason: `Expected the first argument to be an inline function expression`,
|
||||||
@@ -549,10 +548,6 @@ export function dropManualMemoization(func: HIRFunction): void {
|
|||||||
markInstructionIds(func.body);
|
markInstructionIds(func.body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
func.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function findOptionalPlaces(fn: HIRFunction): Set<IdentifierId> {
|
function findOptionalPlaces(fn: HIRFunction): Set<IdentifierId> {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
Place,
|
Place,
|
||||||
isPrimitiveType,
|
isPrimitiveType,
|
||||||
} from '../HIR/HIR';
|
} from '../HIR/HIR';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
import {
|
import {
|
||||||
eachInstructionLValue,
|
eachInstructionLValue,
|
||||||
eachInstructionValueOperand,
|
eachInstructionValueOperand,
|
||||||
@@ -107,7 +108,7 @@ export function inferMutationAliasingRanges(
|
|||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
|
||||||
const errors = new CompilerError();
|
const shouldRecordErrors = !isFunctionExpression && fn.env.enableValidations;
|
||||||
|
|
||||||
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
||||||
const place = param.kind === 'Identifier' ? param : param.place;
|
const place = param.kind === 'Identifier' ? param : param.place;
|
||||||
@@ -200,7 +201,9 @@ export function inferMutationAliasingRanges(
|
|||||||
effect.kind === 'MutateGlobal' ||
|
effect.kind === 'MutateGlobal' ||
|
||||||
effect.kind === 'Impure'
|
effect.kind === 'Impure'
|
||||||
) {
|
) {
|
||||||
errors.pushDiagnostic(effect.error);
|
if (shouldRecordErrors) {
|
||||||
|
fn.env.recordError(effect.error);
|
||||||
|
}
|
||||||
functionEffects.push(effect);
|
functionEffects.push(effect);
|
||||||
} else if (effect.kind === 'Render') {
|
} else if (effect.kind === 'Render') {
|
||||||
renders.push({index: index++, place: effect.place});
|
renders.push({index: index++, place: effect.place});
|
||||||
@@ -245,11 +248,15 @@ export function inferMutationAliasingRanges(
|
|||||||
mutation.kind,
|
mutation.kind,
|
||||||
mutation.place.loc,
|
mutation.place.loc,
|
||||||
mutation.reason,
|
mutation.reason,
|
||||||
errors,
|
shouldRecordErrors ? fn.env : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (const render of renders) {
|
for (const render of renders) {
|
||||||
state.render(render.index, render.place.identifier, errors);
|
state.render(
|
||||||
|
render.index,
|
||||||
|
render.place.identifier,
|
||||||
|
shouldRecordErrors ? fn.env : null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (const param of [...fn.context, ...fn.params]) {
|
for (const param of [...fn.context, ...fn.params]) {
|
||||||
const place = param.kind === 'Identifier' ? param : param.place;
|
const place = param.kind === 'Identifier' ? param : param.place;
|
||||||
@@ -498,7 +505,6 @@ export function inferMutationAliasingRanges(
|
|||||||
* would be transitively mutated needs a capture relationship.
|
* would be transitively mutated needs a capture relationship.
|
||||||
*/
|
*/
|
||||||
const tracked: Array<Place> = [];
|
const tracked: Array<Place> = [];
|
||||||
const ignoredErrors = new CompilerError();
|
|
||||||
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
||||||
const place = param.kind === 'Identifier' ? param : param.place;
|
const place = param.kind === 'Identifier' ? param : param.place;
|
||||||
tracked.push(place);
|
tracked.push(place);
|
||||||
@@ -513,7 +519,7 @@ export function inferMutationAliasingRanges(
|
|||||||
MutationKind.Conditional,
|
MutationKind.Conditional,
|
||||||
into.loc,
|
into.loc,
|
||||||
null,
|
null,
|
||||||
ignoredErrors,
|
null,
|
||||||
);
|
);
|
||||||
for (const from of tracked) {
|
for (const from of tracked) {
|
||||||
if (
|
if (
|
||||||
@@ -547,23 +553,17 @@ export function inferMutationAliasingRanges(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
errors.hasAnyErrors() &&
|
|
||||||
!isFunctionExpression &&
|
|
||||||
fn.env.enableValidations
|
|
||||||
) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
return functionEffects;
|
return functionEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendFunctionErrors(errors: CompilerError, fn: HIRFunction): void {
|
function appendFunctionErrors(env: Environment | null, fn: HIRFunction): void {
|
||||||
|
if (env == null) return;
|
||||||
for (const effect of fn.aliasingEffects ?? []) {
|
for (const effect of fn.aliasingEffects ?? []) {
|
||||||
switch (effect.kind) {
|
switch (effect.kind) {
|
||||||
case 'Impure':
|
case 'Impure':
|
||||||
case 'MutateFrozen':
|
case 'MutateFrozen':
|
||||||
case 'MutateGlobal': {
|
case 'MutateGlobal': {
|
||||||
errors.pushDiagnostic(effect.error);
|
env.recordError(effect.error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -664,7 +664,7 @@ class AliasingState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(index: number, start: Identifier, errors: CompilerError): void {
|
render(index: number, start: Identifier, env: Environment | null): void {
|
||||||
const seen = new Set<Identifier>();
|
const seen = new Set<Identifier>();
|
||||||
const queue: Array<Identifier> = [start];
|
const queue: Array<Identifier> = [start];
|
||||||
while (queue.length !== 0) {
|
while (queue.length !== 0) {
|
||||||
@@ -678,7 +678,7 @@ class AliasingState {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (node.value.kind === 'Function') {
|
if (node.value.kind === 'Function') {
|
||||||
appendFunctionErrors(errors, node.value.function);
|
appendFunctionErrors(env, node.value.function);
|
||||||
}
|
}
|
||||||
for (const [alias, when] of node.createdFrom) {
|
for (const [alias, when] of node.createdFrom) {
|
||||||
if (when >= index) {
|
if (when >= index) {
|
||||||
@@ -710,7 +710,7 @@ class AliasingState {
|
|||||||
startKind: MutationKind,
|
startKind: MutationKind,
|
||||||
loc: SourceLocation,
|
loc: SourceLocation,
|
||||||
reason: MutationReason | null,
|
reason: MutationReason | null,
|
||||||
errors: CompilerError,
|
env: Environment | null,
|
||||||
): void {
|
): void {
|
||||||
const seen = new Map<Identifier, MutationKind>();
|
const seen = new Map<Identifier, MutationKind>();
|
||||||
const queue: Array<{
|
const queue: Array<{
|
||||||
@@ -742,7 +742,7 @@ class AliasingState {
|
|||||||
node.transitive == null &&
|
node.transitive == null &&
|
||||||
node.local == null
|
node.local == null
|
||||||
) {
|
) {
|
||||||
appendFunctionErrors(errors, node.value.function);
|
appendFunctionErrors(env, node.value.function);
|
||||||
}
|
}
|
||||||
if (transitive) {
|
if (transitive) {
|
||||||
if (node.transitive == null || node.transitive.kind < kind) {
|
if (node.transitive == null || node.transitive.kind < kind) {
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ import {
|
|||||||
pruneUnusedLabels,
|
pruneUnusedLabels,
|
||||||
renameVariables,
|
renameVariables,
|
||||||
} from '.';
|
} from '.';
|
||||||
import {CompilerError, ErrorCategory} from '../CompilerError';
|
import {
|
||||||
|
CompilerError,
|
||||||
|
CompilerErrorDetail,
|
||||||
|
ErrorCategory,
|
||||||
|
} from '../CompilerError';
|
||||||
import {Environment, ExternalFunction} from '../HIR';
|
import {Environment, ExternalFunction} from '../HIR';
|
||||||
import {
|
import {
|
||||||
ArrayPattern,
|
ArrayPattern,
|
||||||
@@ -347,10 +351,6 @@ function codegenReactiveFunction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cx.errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(cx.errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
const countMemoBlockVisitor = new CountMemoBlockVisitor(fn.env);
|
const countMemoBlockVisitor = new CountMemoBlockVisitor(fn.env);
|
||||||
visitReactiveFunction(fn, countMemoBlockVisitor, undefined);
|
visitReactiveFunction(fn, countMemoBlockVisitor, undefined);
|
||||||
|
|
||||||
@@ -420,7 +420,6 @@ class Context {
|
|||||||
*/
|
*/
|
||||||
#declarations: Set<DeclarationId> = new Set();
|
#declarations: Set<DeclarationId> = new Set();
|
||||||
temp: Temporaries;
|
temp: Temporaries;
|
||||||
errors: CompilerError = new CompilerError();
|
|
||||||
objectMethods: Map<IdentifierId, ObjectMethod> = new Map();
|
objectMethods: Map<IdentifierId, ObjectMethod> = new Map();
|
||||||
uniqueIdentifiers: Set<string>;
|
uniqueIdentifiers: Set<string>;
|
||||||
fbtOperands: Set<IdentifierId>;
|
fbtOperands: Set<IdentifierId>;
|
||||||
@@ -439,6 +438,10 @@ class Context {
|
|||||||
this.fbtOperands = fbtOperands;
|
this.fbtOperands = fbtOperands;
|
||||||
this.temp = temporaries !== null ? new Map(temporaries) : new Map();
|
this.temp = temporaries !== null ? new Map(temporaries) : new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recordError(error: CompilerErrorDetail): void {
|
||||||
|
this.env.recordError(error);
|
||||||
|
}
|
||||||
get nextCacheIndex(): number {
|
get nextCacheIndex(): number {
|
||||||
return this.#nextCacheIndex++;
|
return this.#nextCacheIndex++;
|
||||||
}
|
}
|
||||||
@@ -775,12 +778,14 @@ function codegenTerminal(
|
|||||||
loc: terminal.init.loc,
|
loc: terminal.init.loc,
|
||||||
});
|
});
|
||||||
if (terminal.init.instructions.length !== 2) {
|
if (terminal.init.instructions.length !== 2) {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: 'Support non-trivial for..in inits',
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: 'Support non-trivial for..in inits',
|
||||||
loc: terminal.init.loc,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: terminal.init.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.emptyStatement();
|
return t.emptyStatement();
|
||||||
}
|
}
|
||||||
const iterableCollection = terminal.init.instructions[0];
|
const iterableCollection = terminal.init.instructions[0];
|
||||||
@@ -796,12 +801,14 @@ function codegenTerminal(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'StoreContext': {
|
case 'StoreContext': {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: 'Support non-trivial for..in inits',
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: 'Support non-trivial for..in inits',
|
||||||
loc: terminal.init.loc,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: terminal.init.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.emptyStatement();
|
return t.emptyStatement();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -872,12 +879,14 @@ function codegenTerminal(
|
|||||||
loc: terminal.test.loc,
|
loc: terminal.test.loc,
|
||||||
});
|
});
|
||||||
if (terminal.test.instructions.length !== 2) {
|
if (terminal.test.instructions.length !== 2) {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: 'Support non-trivial for..of inits',
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: 'Support non-trivial for..of inits',
|
||||||
loc: terminal.init.loc,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: terminal.init.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.emptyStatement();
|
return t.emptyStatement();
|
||||||
}
|
}
|
||||||
const iterableItem = terminal.test.instructions[1];
|
const iterableItem = terminal.test.instructions[1];
|
||||||
@@ -892,12 +901,14 @@ function codegenTerminal(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'StoreContext': {
|
case 'StoreContext': {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: 'Support non-trivial for..of inits',
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: 'Support non-trivial for..of inits',
|
||||||
loc: terminal.init.loc,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: terminal.init.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.emptyStatement();
|
return t.emptyStatement();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1957,22 +1968,26 @@ function codegenInstructionValue(
|
|||||||
} else {
|
} else {
|
||||||
if (t.isVariableDeclaration(stmt)) {
|
if (t.isVariableDeclaration(stmt)) {
|
||||||
const declarator = stmt.declarations[0];
|
const declarator = stmt.declarations[0];
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${
|
new CompilerErrorDetail({
|
||||||
(declarator.id as t.Identifier).name
|
reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${
|
||||||
}'`,
|
(declarator.id as t.Identifier).name
|
||||||
category: ErrorCategory.Todo,
|
}'`,
|
||||||
loc: declarator.loc ?? null,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: declarator.loc ?? null,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.stringLiteral(`TODO handle ${declarator.id}`);
|
return t.stringLiteral(`TODO handle ${declarator.id}`);
|
||||||
} else {
|
} else {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`,
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`,
|
||||||
loc: stmt.loc ?? null,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: stmt.loc ?? null,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.stringLiteral(`TODO handle ${stmt.type}`);
|
return t.stringLiteral(`TODO handle ${stmt.type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ export function validateExhaustiveDependencies(fn: HIRFunction): void {
|
|||||||
loc: place.loc,
|
loc: place.loc,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const error = new CompilerError();
|
|
||||||
let startMemo: StartMemoize | null = null;
|
let startMemo: StartMemoize | null = null;
|
||||||
|
|
||||||
function onStartMemoize(
|
function onStartMemoize(
|
||||||
@@ -143,7 +142,7 @@ export function validateExhaustiveDependencies(fn: HIRFunction): void {
|
|||||||
'all',
|
'all',
|
||||||
);
|
);
|
||||||
if (diagnostic != null) {
|
if (diagnostic != null) {
|
||||||
error.pushDiagnostic(diagnostic);
|
fn.env.recordError(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,15 +207,12 @@ export function validateExhaustiveDependencies(fn: HIRFunction): void {
|
|||||||
effectReportMode,
|
effectReportMode,
|
||||||
);
|
);
|
||||||
if (diagnostic != null) {
|
if (diagnostic != null) {
|
||||||
error.pushDiagnostic(diagnostic);
|
fn.env.recordError(diagnostic);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
false, // isFunctionExpression
|
false, // isFunctionExpression
|
||||||
);
|
);
|
||||||
if (error.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateDependencies(
|
function validateDependencies(
|
||||||
|
|||||||
@@ -6,13 +6,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import {
|
import {CompilerErrorDetail, ErrorCategory} from '../CompilerError';
|
||||||
CompilerError,
|
|
||||||
CompilerErrorDetail,
|
|
||||||
ErrorCategory,
|
|
||||||
} from '../CompilerError';
|
|
||||||
import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
|
import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
|
||||||
import {isHookName} from '../HIR/Environment';
|
import {Environment, isHookName} from '../HIR/Environment';
|
||||||
import {
|
import {
|
||||||
HIRFunction,
|
HIRFunction,
|
||||||
IdentifierId,
|
IdentifierId,
|
||||||
@@ -90,15 +86,14 @@ function joinKinds(a: Kind, b: Kind): Kind {
|
|||||||
export function validateHooksUsage(fn: HIRFunction): void {
|
export function validateHooksUsage(fn: HIRFunction): void {
|
||||||
const unconditionalBlocks = computeUnconditionalBlocks(fn);
|
const unconditionalBlocks = computeUnconditionalBlocks(fn);
|
||||||
|
|
||||||
const errors = new CompilerError();
|
|
||||||
const errorsByPlace = new Map<t.SourceLocation, CompilerErrorDetail>();
|
const errorsByPlace = new Map<t.SourceLocation, CompilerErrorDetail>();
|
||||||
|
|
||||||
function recordError(
|
function trackError(
|
||||||
loc: SourceLocation,
|
loc: SourceLocation,
|
||||||
errorDetail: CompilerErrorDetail,
|
errorDetail: CompilerErrorDetail,
|
||||||
): void {
|
): void {
|
||||||
if (typeof loc === 'symbol') {
|
if (typeof loc === 'symbol') {
|
||||||
errors.pushErrorDetail(errorDetail);
|
fn.env.recordError(errorDetail);
|
||||||
} else {
|
} else {
|
||||||
errorsByPlace.set(loc, errorDetail);
|
errorsByPlace.set(loc, errorDetail);
|
||||||
}
|
}
|
||||||
@@ -118,7 +113,7 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
* If that same place is also used as a conditional call, upgrade the error to a conditonal hook error
|
* If that same place is also used as a conditional call, upgrade the error to a conditonal hook error
|
||||||
*/
|
*/
|
||||||
if (previousError === undefined || previousError.reason !== reason) {
|
if (previousError === undefined || previousError.reason !== reason) {
|
||||||
recordError(
|
trackError(
|
||||||
place.loc,
|
place.loc,
|
||||||
new CompilerErrorDetail({
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Hooks,
|
category: ErrorCategory.Hooks,
|
||||||
@@ -134,7 +129,7 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
const previousError =
|
const previousError =
|
||||||
typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
||||||
if (previousError === undefined) {
|
if (previousError === undefined) {
|
||||||
recordError(
|
trackError(
|
||||||
place.loc,
|
place.loc,
|
||||||
new CompilerErrorDetail({
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Hooks,
|
category: ErrorCategory.Hooks,
|
||||||
@@ -151,7 +146,7 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
const previousError =
|
const previousError =
|
||||||
typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
||||||
if (previousError === undefined) {
|
if (previousError === undefined) {
|
||||||
recordError(
|
trackError(
|
||||||
place.loc,
|
place.loc,
|
||||||
new CompilerErrorDetail({
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Hooks,
|
category: ErrorCategory.Hooks,
|
||||||
@@ -396,7 +391,7 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
case 'ObjectMethod':
|
case 'ObjectMethod':
|
||||||
case 'FunctionExpression': {
|
case 'FunctionExpression': {
|
||||||
visitFunctionExpression(errors, instr.value.loweredFunc.func);
|
visitFunctionExpression(fn.env, instr.value.loweredFunc.func);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@@ -421,20 +416,17 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [, error] of errorsByPlace) {
|
for (const [, error] of errorsByPlace) {
|
||||||
errors.pushErrorDetail(error);
|
fn.env.recordError(error);
|
||||||
}
|
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function visitFunctionExpression(errors: CompilerError, fn: HIRFunction): void {
|
function visitFunctionExpression(env: Environment, fn: HIRFunction): void {
|
||||||
for (const [, block] of fn.body.blocks) {
|
for (const [, block] of fn.body.blocks) {
|
||||||
for (const instr of block.instructions) {
|
for (const instr of block.instructions) {
|
||||||
switch (instr.value.kind) {
|
switch (instr.value.kind) {
|
||||||
case 'ObjectMethod':
|
case 'ObjectMethod':
|
||||||
case 'FunctionExpression': {
|
case 'FunctionExpression': {
|
||||||
visitFunctionExpression(errors, instr.value.loweredFunc.func);
|
visitFunctionExpression(env, instr.value.loweredFunc.func);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'MethodCall':
|
case 'MethodCall':
|
||||||
@@ -445,7 +437,7 @@ function visitFunctionExpression(errors: CompilerError, fn: HIRFunction): void {
|
|||||||
: instr.value.property;
|
: instr.value.property;
|
||||||
const hookKind = getHookKind(fn.env, callee.identifier);
|
const hookKind = getHookKind(fn.env, callee.identifier);
|
||||||
if (hookKind != null) {
|
if (hookKind != null) {
|
||||||
errors.pushErrorDetail(
|
env.recordError(
|
||||||
new CompilerErrorDetail({
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Hooks,
|
category: ErrorCategory.Hooks,
|
||||||
reason:
|
reason:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerError, CompilerErrorDetail, EnvironmentConfig} from '..';
|
import {CompilerErrorDetail, EnvironmentConfig} from '..';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
import {ErrorCategory} from '../CompilerError';
|
||||||
import {HIRFunction, IdentifierId} from '../HIR';
|
import {HIRFunction, IdentifierId} from '../HIR';
|
||||||
import {DEFAULT_GLOBALS} from '../HIR/Globals';
|
import {DEFAULT_GLOBALS} from '../HIR/Globals';
|
||||||
@@ -20,7 +20,6 @@ export function validateNoCapitalizedCalls(fn: HIRFunction): void {
|
|||||||
return ALLOW_LIST.has(name);
|
return ALLOW_LIST.has(name);
|
||||||
};
|
};
|
||||||
|
|
||||||
const errors = new CompilerError();
|
|
||||||
const capitalLoadGlobals = new Map<IdentifierId, string>();
|
const capitalLoadGlobals = new Map<IdentifierId, string>();
|
||||||
const capitalizedProperties = new Map<IdentifierId, string>();
|
const capitalizedProperties = new Map<IdentifierId, string>();
|
||||||
const reason =
|
const reason =
|
||||||
@@ -72,20 +71,19 @@ export function validateNoCapitalizedCalls(fn: HIRFunction): void {
|
|||||||
const propertyIdentifier = value.property.identifier.id;
|
const propertyIdentifier = value.property.identifier.id;
|
||||||
const propertyName = capitalizedProperties.get(propertyIdentifier);
|
const propertyName = capitalizedProperties.get(propertyIdentifier);
|
||||||
if (propertyName != null) {
|
if (propertyName != null) {
|
||||||
errors.push({
|
fn.env.recordError(
|
||||||
category: ErrorCategory.CapitalizedCalls,
|
new CompilerErrorDetail({
|
||||||
reason,
|
category: ErrorCategory.CapitalizedCalls,
|
||||||
description: `${propertyName} may be a component`,
|
reason,
|
||||||
loc: value.loc,
|
description: `${propertyName} may be a component`,
|
||||||
suggestions: null,
|
loc: value.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerError, SourceLocation} from '..';
|
import {CompilerError, SourceLocation} from '..';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
import {CompilerErrorDetail, ErrorCategory} from '../CompilerError';
|
||||||
import {
|
import {
|
||||||
ArrayExpression,
|
ArrayExpression,
|
||||||
BlockId,
|
BlockId,
|
||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
eachInstructionValueOperand,
|
eachInstructionValueOperand,
|
||||||
eachTerminalOperand,
|
eachTerminalOperand,
|
||||||
} from '../HIR/visitors';
|
} from '../HIR/visitors';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates that useEffect is not used for derived computations which could/should
|
* Validates that useEffect is not used for derived computations which could/should
|
||||||
@@ -49,8 +50,6 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
|
|||||||
const functions: Map<IdentifierId, FunctionExpression> = new Map();
|
const functions: Map<IdentifierId, FunctionExpression> = new Map();
|
||||||
const locals: Map<IdentifierId, IdentifierId> = new Map();
|
const locals: Map<IdentifierId, IdentifierId> = new Map();
|
||||||
|
|
||||||
const errors = new CompilerError();
|
|
||||||
|
|
||||||
for (const block of fn.body.blocks.values()) {
|
for (const block of fn.body.blocks.values()) {
|
||||||
for (const instr of block.instructions) {
|
for (const instr of block.instructions) {
|
||||||
const {lvalue, value} = instr;
|
const {lvalue, value} = instr;
|
||||||
@@ -90,20 +89,19 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
|
|||||||
validateEffect(
|
validateEffect(
|
||||||
effectFunction.loweredFunc.func,
|
effectFunction.loweredFunc.func,
|
||||||
dependencies,
|
dependencies,
|
||||||
errors,
|
fn.env,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateEffect(
|
function validateEffect(
|
||||||
effectFunction: HIRFunction,
|
effectFunction: HIRFunction,
|
||||||
effectDeps: Array<IdentifierId>,
|
effectDeps: Array<IdentifierId>,
|
||||||
errors: CompilerError,
|
env: Environment,
|
||||||
): void {
|
): void {
|
||||||
for (const operand of effectFunction.context) {
|
for (const operand of effectFunction.context) {
|
||||||
if (isSetStateType(operand.identifier)) {
|
if (isSetStateType(operand.identifier)) {
|
||||||
@@ -217,13 +215,15 @@ function validateEffect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const loc of setStateLocations) {
|
for (const loc of setStateLocations) {
|
||||||
errors.push({
|
env.recordError(
|
||||||
category: ErrorCategory.EffectDerivationsOfState,
|
new CompilerErrorDetail({
|
||||||
reason:
|
category: ErrorCategory.EffectDerivationsOfState,
|
||||||
'Values derived from props and state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)',
|
reason:
|
||||||
description: null,
|
'Values derived from props and state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)',
|
||||||
loc,
|
description: null,
|
||||||
suggestions: null,
|
loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerDiagnostic, CompilerError, Effect} from '..';
|
import {CompilerDiagnostic, Effect} from '..';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
import {ErrorCategory} from '../CompilerError';
|
||||||
import {
|
import {
|
||||||
HIRFunction,
|
HIRFunction,
|
||||||
@@ -43,7 +43,6 @@ import {AliasingEffect} from '../Inference/AliasingEffects';
|
|||||||
* that are passed where a frozen value is expected and rejects them.
|
* that are passed where a frozen value is expected and rejects them.
|
||||||
*/
|
*/
|
||||||
export function validateNoFreezingKnownMutableFunctions(fn: HIRFunction): void {
|
export function validateNoFreezingKnownMutableFunctions(fn: HIRFunction): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
const contextMutationEffects: Map<
|
const contextMutationEffects: Map<
|
||||||
IdentifierId,
|
IdentifierId,
|
||||||
Extract<AliasingEffect, {kind: 'Mutate'} | {kind: 'MutateTransitive'}>
|
Extract<AliasingEffect, {kind: 'Mutate'} | {kind: 'MutateTransitive'}>
|
||||||
@@ -60,7 +59,7 @@ export function validateNoFreezingKnownMutableFunctions(fn: HIRFunction): void {
|
|||||||
place.identifier.name.kind === 'named'
|
place.identifier.name.kind === 'named'
|
||||||
? `\`${place.identifier.name.value}\``
|
? `\`${place.identifier.name.value}\``
|
||||||
: 'a local variable';
|
: 'a local variable';
|
||||||
errors.pushDiagnostic(
|
fn.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.Immutability,
|
category: ErrorCategory.Immutability,
|
||||||
reason: 'Cannot modify local variables after render completes',
|
reason: 'Cannot modify local variables after render completes',
|
||||||
@@ -159,7 +158,4 @@ export function validateNoFreezingKnownMutableFunctions(fn: HIRFunction): void {
|
|||||||
visitOperand(operand);
|
visitOperand(operand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerDiagnostic, CompilerError} from '..';
|
import {CompilerDiagnostic} from '..';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
import {ErrorCategory} from '../CompilerError';
|
||||||
import {HIRFunction} from '../HIR';
|
import {HIRFunction} from '../HIR';
|
||||||
import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffects';
|
import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffects';
|
||||||
@@ -20,7 +20,6 @@ import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffect
|
|||||||
* and use it here.
|
* and use it here.
|
||||||
*/
|
*/
|
||||||
export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
|
export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
for (const [, block] of fn.body.blocks) {
|
for (const [, block] of fn.body.blocks) {
|
||||||
for (const instr of block.instructions) {
|
for (const instr of block.instructions) {
|
||||||
const value = instr.value;
|
const value = instr.value;
|
||||||
@@ -32,7 +31,7 @@ export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
|
|||||||
callee.identifier.type,
|
callee.identifier.type,
|
||||||
);
|
);
|
||||||
if (signature != null && signature.impure === true) {
|
if (signature != null && signature.impure === true) {
|
||||||
errors.pushDiagnostic(
|
fn.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.Purity,
|
category: ErrorCategory.Purity,
|
||||||
reason: 'Cannot call impure function during render',
|
reason: 'Cannot call impure function during render',
|
||||||
@@ -52,7 +51,4 @@ export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,8 +124,8 @@ export function validateNoRefAccessInRender(fn: HIRFunction): void {
|
|||||||
collectTemporariesSidemap(fn, env);
|
collectTemporariesSidemap(fn, env);
|
||||||
const errors = new CompilerError();
|
const errors = new CompilerError();
|
||||||
validateNoRefAccessInRenderImpl(fn, env, errors);
|
validateNoRefAccessInRenderImpl(fn, env, errors);
|
||||||
if (errors.hasAnyErrors()) {
|
for (const detail of errors.details) {
|
||||||
fn.env.recordErrors(errors);
|
fn.env.recordError(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ export function validateNoSetStateInRender(fn: HIRFunction): void {
|
|||||||
fn,
|
fn,
|
||||||
unconditionalSetStateFunctions,
|
unconditionalSetStateFunctions,
|
||||||
);
|
);
|
||||||
if (errors.hasAnyErrors()) {
|
for (const detail of errors.details) {
|
||||||
fn.env.recordErrors(errors);
|
fn.env.recordError(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
ScopeId,
|
ScopeId,
|
||||||
SourceLocation,
|
SourceLocation,
|
||||||
} from '../HIR';
|
} from '../HIR';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
import {printIdentifier, printManualMemoDependency} from '../HIR/PrintHIR';
|
import {printIdentifier, printManualMemoDependency} from '../HIR/PrintHIR';
|
||||||
import {
|
import {
|
||||||
eachInstructionValueLValue,
|
eachInstructionValueLValue,
|
||||||
@@ -48,11 +49,10 @@ import {getOrInsertDefault} from '../Utils/utils';
|
|||||||
*/
|
*/
|
||||||
export function validatePreservedManualMemoization(fn: ReactiveFunction): void {
|
export function validatePreservedManualMemoization(fn: ReactiveFunction): void {
|
||||||
const state = {
|
const state = {
|
||||||
errors: new CompilerError(),
|
env: fn.env,
|
||||||
manualMemoState: null,
|
manualMemoState: null,
|
||||||
};
|
};
|
||||||
visitReactiveFunction(fn, new Visitor(), state);
|
visitReactiveFunction(fn, new Visitor(), state);
|
||||||
fn.env.recordErrors(state.errors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
@@ -110,7 +110,7 @@ type ManualMemoBlockState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type VisitorState = {
|
type VisitorState = {
|
||||||
errors: CompilerError;
|
env: Environment;
|
||||||
manualMemoState: ManualMemoBlockState | null;
|
manualMemoState: ManualMemoBlockState | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ function validateInferredDep(
|
|||||||
temporaries: Map<IdentifierId, ManualMemoDependency>,
|
temporaries: Map<IdentifierId, ManualMemoDependency>,
|
||||||
declsWithinMemoBlock: Set<DeclarationId>,
|
declsWithinMemoBlock: Set<DeclarationId>,
|
||||||
validDepsInMemoBlock: Array<ManualMemoDependency>,
|
validDepsInMemoBlock: Array<ManualMemoDependency>,
|
||||||
errorState: CompilerError,
|
errorState: Environment,
|
||||||
memoLocation: SourceLocation,
|
memoLocation: SourceLocation,
|
||||||
): void {
|
): void {
|
||||||
let normalizedDep: ManualMemoDependency;
|
let normalizedDep: ManualMemoDependency;
|
||||||
@@ -280,7 +280,7 @@ function validateInferredDep(
|
|||||||
errorDiagnostic = merge(errorDiagnostic ?? compareResult, compareResult);
|
errorDiagnostic = merge(errorDiagnostic ?? compareResult, compareResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errorState.pushDiagnostic(
|
errorState.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.PreserveManualMemo,
|
category: ErrorCategory.PreserveManualMemo,
|
||||||
reason: 'Existing memoization could not be preserved',
|
reason: 'Existing memoization could not be preserved',
|
||||||
@@ -426,7 +426,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
|||||||
this.temporaries,
|
this.temporaries,
|
||||||
state.manualMemoState.decls,
|
state.manualMemoState.decls,
|
||||||
state.manualMemoState.depsFromSource,
|
state.manualMemoState.depsFromSource,
|
||||||
state.errors,
|
state.env,
|
||||||
state.manualMemoState.loc,
|
state.manualMemoState.loc,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -529,7 +529,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
|||||||
!this.scopes.has(identifier.scope.id) &&
|
!this.scopes.has(identifier.scope.id) &&
|
||||||
!this.prunedScopes.has(identifier.scope.id)
|
!this.prunedScopes.has(identifier.scope.id)
|
||||||
) {
|
) {
|
||||||
state.errors.pushDiagnostic(
|
state.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.PreserveManualMemo,
|
category: ErrorCategory.PreserveManualMemo,
|
||||||
reason: 'Existing memoization could not be preserved',
|
reason: 'Existing memoization could not be preserved',
|
||||||
@@ -575,7 +575,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
|||||||
|
|
||||||
for (const identifier of decls) {
|
for (const identifier of decls) {
|
||||||
if (isUnmemoized(identifier, this.scopes)) {
|
if (isUnmemoized(identifier, this.scopes)) {
|
||||||
state.errors.pushDiagnostic(
|
state.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.PreserveManualMemo,
|
category: ErrorCategory.PreserveManualMemo,
|
||||||
reason: 'Existing memoization could not be preserved',
|
reason: 'Existing memoization could not be preserved',
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import {NodePath} from '@babel/traverse';
|
import {NodePath} from '@babel/traverse';
|
||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import {CompilerDiagnostic, CompilerError, ErrorCategory} from '..';
|
import {CompilerDiagnostic, ErrorCategory} from '..';
|
||||||
import {CodegenFunction} from '../ReactiveScopes';
|
import {CodegenFunction} from '../ReactiveScopes';
|
||||||
import {Environment} from '../HIR/Environment';
|
import {Environment} from '../HIR/Environment';
|
||||||
|
|
||||||
@@ -125,8 +125,6 @@ export function validateSourceLocations(
|
|||||||
generatedAst: CodegenFunction,
|
generatedAst: CodegenFunction,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
): void {
|
): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Step 1: Collect important locations from the original source
|
* Step 1: Collect important locations from the original source
|
||||||
* Note: Multiple node types can share the same location (e.g. VariableDeclarator and Identifier)
|
* Note: Multiple node types can share the same location (e.g. VariableDeclarator and Identifier)
|
||||||
@@ -241,7 +239,7 @@ export function validateSourceLocations(
|
|||||||
loc: t.SourceLocation,
|
loc: t.SourceLocation,
|
||||||
nodeType: string,
|
nodeType: string,
|
||||||
): void => {
|
): void => {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.Todo,
|
category: ErrorCategory.Todo,
|
||||||
reason: 'Important source location missing in generated code',
|
reason: 'Important source location missing in generated code',
|
||||||
@@ -261,7 +259,7 @@ export function validateSourceLocations(
|
|||||||
expectedType: string,
|
expectedType: string,
|
||||||
actualTypes: Set<string>,
|
actualTypes: Set<string>,
|
||||||
): void => {
|
): void => {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.Todo,
|
category: ErrorCategory.Todo,
|
||||||
reason:
|
reason:
|
||||||
@@ -309,6 +307,4 @@ export function validateSourceLocations(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
env.recordErrors(errors);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ import {
|
|||||||
IdentifierId,
|
IdentifierId,
|
||||||
SourceLocation,
|
SourceLocation,
|
||||||
} from '../HIR';
|
} from '../HIR';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
import {
|
import {
|
||||||
eachInstructionValueOperand,
|
eachInstructionValueOperand,
|
||||||
eachTerminalOperand,
|
eachTerminalOperand,
|
||||||
} from '../HIR/visitors';
|
} from '../HIR/visitors';
|
||||||
|
|
||||||
export function validateUseMemo(fn: HIRFunction): void {
|
export function validateUseMemo(fn: HIRFunction): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
const voidMemoErrors = new CompilerError();
|
const voidMemoErrors = new CompilerError();
|
||||||
const useMemos = new Set<IdentifierId>();
|
const useMemos = new Set<IdentifierId>();
|
||||||
const react = new Set<IdentifierId>();
|
const react = new Set<IdentifierId>();
|
||||||
@@ -90,7 +90,7 @@ export function validateUseMemo(fn: HIRFunction): void {
|
|||||||
firstParam.kind === 'Identifier'
|
firstParam.kind === 'Identifier'
|
||||||
? firstParam.loc
|
? firstParam.loc
|
||||||
: firstParam.place.loc;
|
: firstParam.place.loc;
|
||||||
errors.pushDiagnostic(
|
fn.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: 'useMemo() callbacks may not accept parameters',
|
reason: 'useMemo() callbacks may not accept parameters',
|
||||||
@@ -106,7 +106,7 @@ export function validateUseMemo(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
|
if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
|
||||||
errors.pushDiagnostic(
|
fn.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason:
|
reason:
|
||||||
@@ -122,7 +122,7 @@ export function validateUseMemo(fn: HIRFunction): void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateNoContextVariableAssignment(body.loweredFunc.func, errors);
|
validateNoContextVariableAssignment(body.loweredFunc.func, fn.env);
|
||||||
|
|
||||||
if (fn.env.config.validateNoVoidUseMemo) {
|
if (fn.env.config.validateNoVoidUseMemo) {
|
||||||
if (!hasNonVoidReturn(body.loweredFunc.func)) {
|
if (!hasNonVoidReturn(body.loweredFunc.func)) {
|
||||||
@@ -176,14 +176,11 @@ export function validateUseMemo(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn.env.logErrors(voidMemoErrors.asResult());
|
fn.env.logErrors(voidMemoErrors.asResult());
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateNoContextVariableAssignment(
|
function validateNoContextVariableAssignment(
|
||||||
fn: HIRFunction,
|
fn: HIRFunction,
|
||||||
errors: CompilerError,
|
env: Environment,
|
||||||
): void {
|
): void {
|
||||||
const context = new Set(fn.context.map(place => place.identifier.id));
|
const context = new Set(fn.context.map(place => place.identifier.id));
|
||||||
for (const block of fn.body.blocks.values()) {
|
for (const block of fn.body.blocks.values()) {
|
||||||
@@ -192,7 +189,7 @@ function validateNoContextVariableAssignment(
|
|||||||
switch (value.kind) {
|
switch (value.kind) {
|
||||||
case 'StoreContext': {
|
case 'StoreContext': {
|
||||||
if (context.has(value.lvalue.place.identifier.id)) {
|
if (context.has(value.lvalue.place.identifier.id)) {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason:
|
reason:
|
||||||
|
|||||||
Reference in New Issue
Block a user