Skip to content

Conversation

josephsavona
Copy link
Member

@josephsavona josephsavona commented Jun 4, 2025

Stack from ghstack (oldest at bottom):

Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact, the only things that can throw their lvalue are call expressions! c = a.b can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

This was referenced Jun 3, 2025
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Jun 4, 2025
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[ghstack-poisoned]
Adds explicit freeze effects for Return terminals and, more importantly, adds effects for MaybeThrow terminals. MaybeThrow is super interesting. The idea of the terminal is to represent that control-flow can break from nearly any instruction to the error handler (catch). InferMutableRanges has a pass that explicitly handles the corresponding data flow, saying that for any instruction in a block ending in MaybeThrow, to alias the instruction's lvalue to the catch handler. This is to handle cases like this:

```js
const x = [];
try {
  throwInput(x);
} catch (x_alias) {
  mutate(x_alias); // mutates x!
}
```

One realization is that this logic was overly pessimistic: most instruction types cannot actually throw their lvalue. In fact,  the only things that can throw their lvalue are call expressions! `c = a.b` can throw, for example, but only with an error generated by the runtime, not with a user value.

Doing this allows us to encode the data flow once and then not have to handle wiring up this data again later.

[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