mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Fix evaluation order for JSX element tags
When lowering a JSX element we were correctly lowering to a temporary in all but one case: the common case of an identifier. That is fine in practice but breaks in the presence of the tag identifier being reassigned in the props/children. This PR fixes to always lower the tag to a temporary.
This commit is contained in:
@@ -27,7 +27,6 @@ import {
|
||||
InstructionKind,
|
||||
InstructionValue,
|
||||
JsxAttribute,
|
||||
makeInstructionId,
|
||||
ObjectPattern,
|
||||
ObjectProperty,
|
||||
Place,
|
||||
@@ -35,6 +34,7 @@ import {
|
||||
SourceLocation,
|
||||
SpreadPattern,
|
||||
ThrowTerminal,
|
||||
makeInstructionId,
|
||||
} from "./HIR";
|
||||
import HIRBuilder, { Bindings } from "./HIRBuilder";
|
||||
|
||||
@@ -2041,7 +2041,11 @@ function lowerJsxElementName(
|
||||
if (exprPath.isJSXIdentifier()) {
|
||||
const tag: string = exprPath.node.name;
|
||||
if (tag.match(/^[A-Z]/)) {
|
||||
return lowerIdentifier(builder, exprPath);
|
||||
return lowerValueToTemporary(builder, {
|
||||
kind: "LoadLocal",
|
||||
place: lowerIdentifier(builder, exprPath),
|
||||
loc: exprLoc,
|
||||
});
|
||||
} else {
|
||||
if (tag.indexOf(":") !== -1) {
|
||||
builder.errors.push({
|
||||
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const maybeMutable = new MaybeMutable();
|
||||
let Tag = View;
|
||||
// NOTE: the order of evaluation in the lowering is incorrect:
|
||||
// the jsx element's tag observes `Tag` after reassignment, but should observe
|
||||
// it before the reassignment.
|
||||
return (
|
||||
<Tag>
|
||||
{((Tag = HScroll), maybeMutate(maybeMutable))}
|
||||
<Tag />
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import * as React from "react";
|
||||
function Component(props) {
|
||||
const $ = React.unstable_useMemoCache(5);
|
||||
let Tag;
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const maybeMutable = new MaybeMutable();
|
||||
|
||||
t0 = "\n ";
|
||||
Tag = HScroll;
|
||||
t1 = maybeMutate(maybeMutable);
|
||||
$[0] = Tag;
|
||||
$[1] = t0;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
Tag = $[0];
|
||||
t0 = $[1];
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t2 = <Tag />;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
let t3;
|
||||
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = (
|
||||
<Tag>
|
||||
{t0}
|
||||
{t1}
|
||||
{t2}
|
||||
</Tag>
|
||||
);
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const maybeMutable = new MaybeMutable();
|
||||
let Tag = props.component;
|
||||
// NOTE: the order of evaluation in the lowering is incorrect:
|
||||
// the jsx element's tag observes `Tag` after reassignment, but should observe
|
||||
// it before the reassignment.
|
||||
return (
|
||||
<Tag>
|
||||
{((Tag = props.alternateComponent), maybeMutate(maybeMutable))}
|
||||
<Tag />
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] Invariant: [Codegen] No value found for temporary. Value for 'read $33' was not set in the codegen context (8:8)
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
function Component(props) {
|
||||
const maybeMutable = new MaybeMutable();
|
||||
let Tag = View;
|
||||
let Tag = props.component;
|
||||
// NOTE: the order of evaluation in the lowering is incorrect:
|
||||
// the jsx element's tag observes `Tag` after reassignment, but should observe
|
||||
// it before the reassignment.
|
||||
return (
|
||||
<Tag>
|
||||
{((Tag = HScroll), maybeMutate(maybeMutable))}
|
||||
{((Tag = props.alternateComponent), maybeMutate(maybeMutable))}
|
||||
<Tag />
|
||||
</Tag>
|
||||
);
|
||||
+1
-1
@@ -25,7 +25,7 @@ function Component(props) {
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidInput: InferReferenceEffects: inferred mutation of known immutable value. Found mutation of $43:TObject<BuiltInArray> (frozen) (13:13)
|
||||
[ReactForget] InvalidInput: InferReferenceEffects: inferred mutation of known immutable value. Found mutation of $46:TObject<BuiltInArray> (frozen) (13:13)
|
||||
```
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ function Component(props) {
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidInput: InferReferenceEffects: inferred mutation of known immutable value. Found mutation of $26:TObject<BuiltInArray> (frozen) (7:7)
|
||||
[ReactForget] InvalidInput: InferReferenceEffects: inferred mutation of known immutable value. Found mutation of $28:TObject<BuiltInArray> (frozen) (7:7)
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
let Tag = View;
|
||||
return (
|
||||
<Tag>
|
||||
{((Tag = HScroll), props.value)}
|
||||
<Tag />
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import * as React from "react";
|
||||
function Component(props) {
|
||||
const $ = React.unstable_useMemoCache(3);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <HScroll />;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const c_1 = $[1] !== props.value;
|
||||
let t1;
|
||||
if (c_1) {
|
||||
t1 = (
|
||||
<View>
|
||||
{props.value}
|
||||
{t0}
|
||||
</View>
|
||||
);
|
||||
$[1] = props.value;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
function Component(props) {
|
||||
let Tag = View;
|
||||
return (
|
||||
<Tag>
|
||||
{((Tag = HScroll), props.value)}
|
||||
<Tag />
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user