Repository: facebook/react
Pull request: Flow upgrade to 0.175

Stack from [ghstack](https://github.com/ezyang/ghstack) (oldest at bottom):
* #25419
* #25418
* __->__ #25417
* #25416



Changed files:
filename: packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js
patch: @@ -257,7 +257,6 @@ const tests = {
       code: normalizeIndent`
         // Valid because they're not matching use[A-Z].
         fooState();
-        use();
         _use();
         _useState();
         use_hook();
@@ -496,8 +495,6 @@ const tests = {
     },
     {
       code: normalizeIndent`
-        Hook.use();
-        Hook._use();
         Hook.useState();
         Hook._useState();
         Hook.use42();
@@ -1146,6 +1143,45 @@ if (__EXPERIMENTAL__) {
         }
       `,
     },
+    {
+      code: normalizeIndent`
+        function App() {
+          const text = use(Promise.resolve('A'));
+          return <Text text={text} />
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        function App() {
+          if (shouldShowText) {
+            const text = use(query);
+            return <Text text={text} />
+          }
+          return <Text text={shouldFetchBackupText ? use(backupQuery) : "Nothing to see here"} />
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        function App() {
+          let data = [];
+          for (const query of queries) {
+            const text = use(item);
+            data.push(text);
+          }
+          return <Child data={data} />
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        function App() {
+          const data = someCallback((x) => use(x));
+          return <Child data={data} />
+        }
+      `,
+    },
   ];
   tests.invalid = [
     ...tests.invalid,
@@ -1220,6 +1256,50 @@ if (__EXPERIMENTAL__) {
       `,
       errors: [useEventError('onClick')],
     },
+    {
+      code: normalizeIndent`
+        Hook.use();
+        Hook._use();
+        Hook.useState();
+        Hook._useState();
+        Hook.use42();
+        Hook.useHook();
+        Hook.use_hook();
+      `,
+      errors: [
+        topLevelError('Hook.use'),
+        topLevelError('Hook.useState'),
+        topLevelError('Hook.use42'),
+        topLevelError('Hook.useHook'),
+      ],
+    },
+    {
+      code: normalizeIndent`
+        function notAComponent() {
+          use(promise);
+        }
+      `,
+      errors: [functionError('use', 'notAComponent')],
+    },
+    {
+      code: normalizeIndent`
+        const text = use(promise);
+        function App() {
+          return <Text text={text} />
+        }
+      `,
+      errors: [topLevelError('use')],
+    },
+    {
+      code: normalizeIndent`
+        class C {
+          m() {
+            use(promise);
+          }
+        }
+      `,
+      errors: [classError('use')],
+    },
   ];
 }
 

filename: packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
patch: @@ -16,6 +16,9 @@
  */
 
 function isHookName(s) {
+  if (__EXPERIMENTAL__) {
+    return s === 'use' || /^use[A-Z0-9]/.test(s);
+  }
   return /^use[A-Z0-9]/.test(s);
 }
 
@@ -107,6 +110,13 @@ function isUseEventIdentifier(node) {
   return false;
 }
 
+function isUseIdentifier(node) {
+  if (__EXPERIMENTAL__) {
+    return node.type === 'Identifier' && node.name === 'use';
+  }
+  return false;
+}
+
 export default {
   meta: {
     type: 'problem',
@@ -458,7 +468,8 @@ export default {
 
           for (const hook of reactHooks) {
             // Report an error if a hook may be called more then once.
-            if (cycled) {
+            // `use(...)` can be called in loops.
+            if (cycled && !isUseIdentifier(hook)) {
               context.report({
                 node: hook,
                 message:
@@ -479,7 +490,11 @@ export default {
               // path segments.
               //
               // Special case when we think there might be an early return.
-              if (!cycled && pathsFromStartToEnd !== allPathsFromStartToEnd) {
+              if (
+                !cycled &&
+                pathsFromStartToEnd !== allPathsFromStartToEnd &&
+                !isUseIdentifier(hook) // `use(...)` can be called conditionally.
+              ) {
                 const message =
                   `React Hook "${context.getSource(hook)}" is called ` +
                   'conditionally. React Hooks must be called in the exact ' +
@@ -525,7 +540,8 @@ export default {
               // anonymous function expressions. Hopefully this is clarifying
               // enough in the common case that the incorrect message in
               // uncommon cases doesn't matter.
-              if (isSomewhereInsideComponentOrHook) {
+              // `use(...)` can be called in callbacks.
+              if (isSomewhereInsideComponentOrHook && !isUseIdentifier(hook)) {
                 const message =
                   `React Hook "${context.getSource(hook)}" cannot be called ` +
                   'inside a callback. React Hooks must be called in a ' +