mirror of
https://github.com/morluto/rea
synced 2026-10-27 22:45:19 -04:00
fix(javascript): distinguish Map lookups from network endpoints
Resolve unchanged Map operations through shared binding, capture, mutation, and ambient escape facts. Reuse that proof in application and captured bundle analysis; unresolved get/delete receivers remain inferred candidates. Preserve repeated native operations without manufacturing receiver escapes. Retain uncertainty for real escapes, opaque eval, and changed constructor adder hooks. Converge stored aliases at the producing boundary. Adapt the JavaScript changes from #4863, excluding its Linux resource fix. Add captured-bundle parity, repeated-operation and constructor-hook coverage. Fixes #4853 Co-authored-by: abdooo2235 <abdalrhmantheiv15@gmail.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import * as t from "@babel/types";
|
||||
import { unwrapJavaScriptExpression } from "./javascriptAstValues.js";
|
||||
import { createAmbientPathResolver } from "./javascriptSemanticAmbientWrites.js";
|
||||
import { createSemanticModuleInterop } from "./javascriptModuleInterop.js";
|
||||
import {
|
||||
semanticEffectTiming,
|
||||
semanticBindingEffectFollowsCapture,
|
||||
@@ -13,14 +15,20 @@ import {
|
||||
|
||||
/** One source owns sites and the minimal scope tree reaching them; O(AST) storage. */
|
||||
export interface JavaScriptOpaqueScopeEffects {
|
||||
/** Cheap source evidence collected with declarations, before alias queries. */
|
||||
mayReferenceGlobalEval: boolean;
|
||||
readonly sites: WeakSet<t.Node>;
|
||||
readonly sloppySites: WeakSet<t.Node>;
|
||||
readonly byScope: Map<string, t.CallExpression[]>;
|
||||
readonly children: Map<string, Set<string>>;
|
||||
readonly globalSites: (t.CallExpression | t.OptionalCallExpression)[];
|
||||
}
|
||||
|
||||
export const indexSemanticOpaqueEffects = (
|
||||
candidates: readonly { node: t.CallExpression; scopeId: string }[],
|
||||
candidates: readonly {
|
||||
node: t.CallExpression;
|
||||
scopeId: string;
|
||||
}[],
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): void => {
|
||||
for (const { node, scopeId } of candidates) {
|
||||
@@ -44,6 +52,44 @@ export const indexSemanticOpaqueEffects = (
|
||||
}
|
||||
};
|
||||
|
||||
/** The existing ambient invocation walk owns global effects; ordinary sources
|
||||
* neither retain a second call list nor create another alias resolver. */
|
||||
export const createSemanticOpaqueGlobalObserver = (
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): ((node: t.Node) => void) | undefined => {
|
||||
if (!state.opaqueEffects.mayReferenceGlobalEval) return undefined;
|
||||
const ambientPaths = createAmbientPathResolver(state, true);
|
||||
let invocationSite: t.Node | undefined;
|
||||
const interop = createSemanticModuleInterop(state, {
|
||||
intrinsicPath: (node) => {
|
||||
const paths = ambientPaths(node, invocationSite);
|
||||
const path = paths.find((path) => path[1] === "eval") ?? paths[0];
|
||||
if (path?.[0] !== "global" || path.some((key) => key === null))
|
||||
return undefined;
|
||||
// Keep the global callable owner for generic call/apply/bind resolution.
|
||||
return path[1] === "eval"
|
||||
? ["intrinsic", ...(path as readonly string[])]
|
||||
: ["intrinsic", ...(path.slice(1) as readonly string[])];
|
||||
},
|
||||
});
|
||||
return (node) => {
|
||||
if (!t.isCallExpression(node) && !t.isOptionalCallExpression(node)) return;
|
||||
invocationSite = node;
|
||||
const invocation = interop.intrinsicInvocation(node);
|
||||
if (invocation?.path.join(".") === "intrinsic.global.eval")
|
||||
state.opaqueEffects.globalSites.push(node);
|
||||
};
|
||||
};
|
||||
|
||||
/** Indirect eval can change globals, but cannot rebind its caller's locals. */
|
||||
export const semanticOpaqueGlobalMayHaveChanged = (
|
||||
read: t.Node,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): boolean =>
|
||||
state.opaqueEffects.globalSites.some(
|
||||
(effect) => semanticEffectTiming(read, effect, state) !== "after",
|
||||
);
|
||||
|
||||
/** Rebinding requires lexical visibility. Object references can remain reachable
|
||||
* through aliases even where the original name is shadowed or out of block scope.
|
||||
* Without a disjointness proof, consider their enclosing activation and closures.
|
||||
|
||||
Reference in New Issue
Block a user