Skip to content

[compiler] Foundation of new mutability and aliasing (alternate take) #33346

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

Draft
wants to merge 4 commits into
base: gh/josephsavona/92/base
Choose a base branch
from

Conversation

josephsavona
Copy link
Member

@josephsavona josephsavona commented May 22, 2025

Stack from ghstack (oldest at bottom):

Alternate take at a new mutability and alising model, aiming to replace InferReferenceEffects and InferMutableRanges. My initial passes at this were more complicated than necessary, and I've iterated to refine and distill this down to the core concepts. There are two effects that track information flow: capture and alias:

  • Given distinct values A and B. After capture A -> B, mutate(B) does not modify A. This more precisely captures the semantic of the previous Store effect. As an example, array.push(item) has the effect capture item -> array and mutate(array). The array is modified, not the item.
  • Given distinct values A and B. After alias A -> B, mutate(B) does modify A. This is because B now refers to the same value as A.
  • Given distinct values A and B, after either capture A -> B or alias A -> B, transitiveMutate(B) counts as a mutation of A. Transitive mutation is the default, and places that previously used Store will use non-transitive mutate effects instead.

Conceptually "capture A -> B" means that a reference to A was "captured" (or stored) within A, but there is not a directly aliasing. Whereas "alias A -> B" means literal value aliasing.

The idea is that our previous sequential fixpoint loops in InferMutableRanges can instead work by first looking at transitive mutations, then look at non-transitive mutations. And aliasing groups can be built purely based on the alias effect.

Lots more to do here but the structure is coming together.

Alternate take at a new mutability and alising model, aiming to replace `InferReferenceEffects` and `InferMutableRanges`. My initial passes at this were more complicated than necessary, and I've iterated to refine and distill this down to the core concepts. There are two effects that track information flow: `capture` and `alias`:

* Given distinct values A and B. After capture A -> B, mutate(B) does *not* modify A. This more precisely captures the semantic of the previous `Store` effect. As an example, `array.push(item)` has the effect `capture item -> array` and `mutate(array)`. The array is modified, not the item.
* Given distinct values A and B. After alias A -> B, mutate(B) *does* modify A. This is because B now refers to the same value as A.
* Given distinct values A and B, after *either* capture A -> B *or* alias A -> B, transitiveMutate(B) counts as a mutation of A.

Conceptually "capture A -> B" means that a reference to A was "captured" (or stored) within A, but there is not a directly aliasing. Whereas "alias A -> B" means literal value aliasing.

The idea is that our previous sequential fixpoint loops in InferMutableRanges can instead work by first looking at transitive mutations, then look at non-transitive mutations. And aliasing groups can be built purely based on the `alias` effect.

Lots more to do here but the structure is coming together.

[ghstack-poisoned]
josephsavona added a commit that referenced this pull request May 22, 2025
Alternate take at a new mutability and alising model, aiming to replace `InferReferenceEffects` and `InferMutableRanges`. My initial passes at this were more complicated than necessary, and I've iterated to refine and distill this down to the core concepts. There are two effects that track information flow: `capture` and `alias`:

* Given distinct values A and B. After capture A -> B, mutate(B) does *not* modify A. This more precisely captures the semantic of the previous `Store` effect. As an example, `array.push(item)` has the effect `capture item -> array` and `mutate(array)`. The array is modified, not the item.
* Given distinct values A and B. After alias A -> B, mutate(B) *does* modify A. This is because B now refers to the same value as A.
* Given distinct values A and B, after *either* capture A -> B *or* alias A -> B, transitiveMutate(B) counts as a mutation of A.

Conceptually "capture A -> B" means that a reference to A was "captured" (or stored) within A, but there is not a directly aliasing. Whereas "alias A -> B" means literal value aliasing.

The idea is that our previous sequential fixpoint loops in InferMutableRanges can instead work by first looking at transitive mutations, then look at non-transitive mutations. And aliasing groups can be built purely based on the `alias` effect.

Lots more to do here but the structure is coming together.

ghstack-source-id: c4f311d
Pull Request resolved: #33346
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label May 22, 2025
…rnate take)"


Alternate take at a new mutability and alising model, aiming to replace `InferReferenceEffects` and `InferMutableRanges`. My initial passes at this were more complicated than necessary, and I've iterated to refine and distill this down to the core concepts. There are two effects that track information flow: `capture` and `alias`:

* Given distinct values A and B. After capture A -> B, mutate(B) does *not* modify A. This more precisely captures the semantic of the previous `Store` effect. As an example, `array.push(item)` has the effect `capture item -> array` and `mutate(array)`. The array is modified, not the item.
* Given distinct values A and B. After alias A -> B, mutate(B) *does* modify A. This is because B now refers to the same value as A.
* Given distinct values A and B, after *either* capture A -> B *or* alias A -> B, transitiveMutate(B) counts as a mutation of A. Transitive mutation is the default, and places that previously used `Store` will use non-transitive mutate effects instead.

Conceptually "capture A -> B" means that a reference to A was "captured" (or stored) within A, but there is not a directly aliasing. Whereas "alias A -> B" means literal value aliasing.

The idea is that our previous sequential fixpoint loops in InferMutableRanges can instead work by first looking at transitive mutations, then look at non-transitive mutations. And aliasing groups can be built purely based on the `alias` effect.

Lots more to do here but the structure is coming together.

[ghstack-poisoned]
josephsavona added a commit that referenced this pull request May 23, 2025
Alternate take at a new mutability and alising model, aiming to replace `InferReferenceEffects` and `InferMutableRanges`. My initial passes at this were more complicated than necessary, and I've iterated to refine and distill this down to the core concepts. There are two effects that track information flow: `capture` and `alias`:

* Given distinct values A and B. After capture A -> B, mutate(B) does *not* modify A. This more precisely captures the semantic of the previous `Store` effect. As an example, `array.push(item)` has the effect `capture item -> array` and `mutate(array)`. The array is modified, not the item.
* Given distinct values A and B. After alias A -> B, mutate(B) *does* modify A. This is because B now refers to the same value as A.
* Given distinct values A and B, after *either* capture A -> B *or* alias A -> B, transitiveMutate(B) counts as a mutation of A.

Conceptually "capture A -> B" means that a reference to A was "captured" (or stored) within A, but there is not a directly aliasing. Whereas "alias A -> B" means literal value aliasing.

The idea is that our previous sequential fixpoint loops in InferMutableRanges can instead work by first looking at transitive mutations, then look at non-transitive mutations. And aliasing groups can be built purely based on the `alias` effect.

Lots more to do here but the structure is coming together.

ghstack-source-id: 5b9c88a
Pull Request resolved: #33346
import DisjointSet from '../Utils/DisjointSet';
import {inferMutableRangesForAlias} from './InferMutableRangesForAlias';

export function inferMutationAliasingRanges(fn: HIRFunction): void {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still thinking through the cases here. I need to prove to myself that we don't need a fixpoint anymore

…rnate take)"


Alternate take at a new mutability and alising model, aiming to replace `InferReferenceEffects` and `InferMutableRanges`. My initial passes at this were more complicated than necessary, and I've iterated to refine and distill this down to the core concepts. There are two effects that track information flow: `capture` and `alias`:

* Given distinct values A and B. After capture A -> B, mutate(B) does *not* modify A. This more precisely captures the semantic of the previous `Store` effect. As an example, `array.push(item)` has the effect `capture item -> array` and `mutate(array)`. The array is modified, not the item.
* Given distinct values A and B. After alias A -> B, mutate(B) *does* modify A. This is because B now refers to the same value as A.
* Given distinct values A and B, after *either* capture A -> B *or* alias A -> B, transitiveMutate(B) counts as a mutation of A. Transitive mutation is the default, and places that previously used `Store` will use non-transitive mutate effects instead.

Conceptually "capture A -> B" means that a reference to A was "captured" (or stored) within A, but there is not a directly aliasing. Whereas "alias A -> B" means literal value aliasing.

The idea is that our previous sequential fixpoint loops in InferMutableRanges can instead work by first looking at transitive mutations, then look at non-transitive mutations. And aliasing groups can be built purely based on the `alias` effect.

Lots more to do here but the structure is coming together.

[ghstack-poisoned]
…rnate take)"


Alternate take at a new mutability and alising model, aiming to replace `InferReferenceEffects` and `InferMutableRanges`. My initial passes at this were more complicated than necessary, and I've iterated to refine and distill this down to the core concepts. There are two effects that track information flow: `capture` and `alias`:

* Given distinct values A and B. After capture A -> B, mutate(B) does *not* modify A. This more precisely captures the semantic of the previous `Store` effect. As an example, `array.push(item)` has the effect `capture item -> array` and `mutate(array)`. The array is modified, not the item.
* Given distinct values A and B. After alias A -> B, mutate(B) *does* modify A. This is because B now refers to the same value as A.
* Given distinct values A and B, after *either* capture A -> B *or* alias A -> B, transitiveMutate(B) counts as a mutation of A. Transitive mutation is the default, and places that previously used `Store` will use non-transitive mutate effects instead.

Conceptually "capture A -> B" means that a reference to A was "captured" (or stored) within A, but there is not a directly aliasing. Whereas "alias A -> B" means literal value aliasing.

The idea is that our previous sequential fixpoint loops in InferMutableRanges can instead work by first looking at transitive mutations, then look at non-transitive mutations. And aliasing groups can be built purely based on the `alias` effect.

Lots more to do here but the structure is coming together.

[ghstack-poisoned]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants