-
Notifications
You must be signed in to change notification settings - Fork 48.7k
[compiler][newinference] Fixes for transitive function capturing, mutation via property loads #33430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[compiler][newinference] Fixes for transitive function capturing, mutation via property loads #33430
Changes from all commits
4da1c43
752fff2
4469890
f6b9675
b6c382a
680dd2e
2d6d353
e838a4b
26fd4e4
d04d54f
eb3d732
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -155,7 +155,7 @@ export function inferMutationAliasingEffects( | |
} | ||
queue(fn.body.entry, initialState); | ||
|
||
const context = new Context(isFunctionExpression); | ||
const context = new Context(isFunctionExpression, fn); | ||
|
||
let count = 0; | ||
while (queuedStates.size !== 0) { | ||
|
@@ -193,9 +193,11 @@ class Context { | |
new Map(); | ||
catchHandlers: Map<BlockId, Place> = new Map(); | ||
isFuctionExpression: boolean; | ||
fn: HIRFunction; | ||
|
||
constructor(isFunctionExpression: boolean) { | ||
constructor(isFunctionExpression: boolean, fn: HIRFunction) { | ||
this.isFuctionExpression = isFunctionExpression; | ||
this.fn = fn; | ||
} | ||
} | ||
|
||
|
@@ -309,8 +311,14 @@ function applySignature( | |
) { | ||
const aliasingEffects = | ||
instruction.value.loweredFunc.func.aliasingEffects ?? []; | ||
const context = new Set( | ||
instruction.value.loweredFunc.func.context.map(p => p.identifier.id), | ||
); | ||
for (const effect of aliasingEffects) { | ||
if (effect.kind === 'Mutate' || effect.kind === 'MutateTransitive') { | ||
if (!context.has(effect.value.identifier.id)) { | ||
continue; | ||
} | ||
const value = state.kind(effect.value); | ||
switch (value.kind) { | ||
case ValueKind.Global: | ||
|
@@ -458,7 +466,7 @@ function applyEffect( | |
default: { | ||
effects.push({ | ||
// OK: recording information flow | ||
kind: 'Alias', | ||
kind: 'CreateFrom', // prev Alias | ||
from: effect.from, | ||
into: effect.into, | ||
}); | ||
|
@@ -467,6 +475,7 @@ function applyEffect( | |
break; | ||
} | ||
case 'CreateFunction': { | ||
effects.push(effect); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a consistent theme is that effects should almost always be preserved rather than dropped, so that range analysis can understand them. here, we want to know about the creation |
||
const isMutable = effect.captures.some(capture => { | ||
switch (state.kind(capture).kind) { | ||
case ValueKind.Context: | ||
|
@@ -644,6 +653,13 @@ function applyEffect( | |
if (DEBUG) { | ||
console.log('apply function expression effects'); | ||
} | ||
applyEffect( | ||
context, | ||
state, | ||
{kind: 'MutateTransitiveConditionally', value: effect.function}, | ||
aliased, | ||
effects, | ||
); | ||
Comment on lines
+656
to
+662
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. even if we're able to construct a signature for a local function expression, we still need to consider it as mutating to account for mutations of its captures. |
||
for (const signatureEffect of signatureEffects) { | ||
applyEffect(context, state, signatureEffect, aliased, effects); | ||
} | ||
|
@@ -1587,10 +1603,26 @@ function computeSignatureForInstruction( | |
break; | ||
} | ||
case 'StoreGlobal': { | ||
CompilerError.throwTodo({ | ||
reason: `Handle StoreGlobal in new inference`, | ||
loc: instr.loc, | ||
effects.push({ | ||
kind: 'MutateGlobal', | ||
place: value.value, | ||
error: { | ||
severity: ErrorSeverity.InvalidReact, | ||
reason: getWriteErrorReason({ | ||
kind: ValueKind.Global, | ||
reason: new Set([ValueReason.Global]), | ||
context: new Set(), | ||
}), | ||
description: | ||
value.value.identifier.name !== null && | ||
value.value.identifier.name.kind === 'named' | ||
? `Found mutation of \`${value.value.identifier.name}\`` | ||
: null, | ||
loc: value.value.loc, | ||
suggestions: null, | ||
}, | ||
}); | ||
break; | ||
} | ||
case 'TypeCastExpression': { | ||
effects.push({kind: 'Assign', from: value.value, into: lvalue}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function expression effects now include effects for params, but these values won't exist in the outer context so we skip them