Repository: vercel/next.js
Pull request: Turbopack: Make `ReadVcFuture::strongly_consistent` private

This method is needed with `turbo-tasks` to implement `OperationVc`, but exposing it to other crates turns it into a footgun, because it allows you to attempt to read a `Vc` or `ResolvedVc` with strong consistency, which doesn't have a well-defined meaning.

Changed files:
filename: crates/next-api/src/project.rs
patch: @@ -2253,43 +2253,40 @@ impl Project {
         }
     }
 
-    /// Get HMR version for the specified target.
-    #[turbo_tasks::function]
-    async fn hmr_version(
-        self: Vc<Self>,
-        chunk_name: RcStr,
-        target: HmrTarget,
-    ) -> Result<Vc<Box<dyn Version>>> {
-        let content = self.hmr_content(chunk_name, target).await?;
-        if let Some(content) = &*content {
-            Ok(content.version())
-        } else {
-            Ok(Vc::upcast(NotFoundVersion::new()))
-        }
-    }
-
     /// Get the version state for an HMR session. Initialized with the first seen
     /// version in that session.
     #[turbo_tasks::function]
     pub async fn hmr_version_state(
-        self: Vc<Self>,
+        self: ResolvedVc<Self>,
         chunk_name: RcStr,
         target: HmrTarget,
         session: TransientInstance<()>,
     ) -> Result<Vc<VersionState>> {
-        let version = self.hmr_version(chunk_name, target);
-
         // The session argument is important to avoid caching this function between
         // sessions.
         let _ = session;
 
+        #[turbo_tasks::function(operation)]
+        async fn hmr_version_operation(
+            this: ResolvedVc<Project>,
+            chunk_name: RcStr,
+            target: HmrTarget,
+        ) -> Result<Vc<Box<dyn Version>>> {
+            let content = this.hmr_content(chunk_name, target).await?;
+            if let Some(content) = &*content {
+                Ok(content.version())
+            } else {
+                Ok(Vc::upcast(NotFoundVersion::new()))
+            }
+        }
+        let version_op = hmr_version_operation(self, chunk_name, target);
+
         // INVALIDATION: This is intentionally untracked to avoid invalidating this
         // function completely. We want to initialize the VersionState with the
         // first seen version of the session.
         let state = VersionState::new(
-            version
-                .into_trait_ref()
-                .strongly_consistent()
+            version_op
+                .read_trait_strongly_consistent()
                 .untracked()
                 .await?,
         )

filename: turbopack/crates/turbo-tasks/src/vc/operation.rs
patch: @@ -7,8 +7,8 @@ use serde::{Deserialize, Serialize};
 pub use turbo_tasks_macros::OperationValue;
 
 use crate::{
-    CollectiblesSource, IntoTraitRef, RawVc, ReadVcFuture, ResolvedVc, TaskInput, TraitRef,
-    UpcastStrict, Vc, VcValueTrait, VcValueType, marker_trait::impl_auto_marker_trait,
+    CollectiblesSource, IntoTraitRef, RawVc, ReadVcFuture, ResolvedVc, TaskInput, UpcastStrict, Vc,
+    VcValueTrait, VcValueTraitCast, VcValueType, marker_trait::impl_auto_marker_trait,
     trace::TraceRawVcs,
 };
 
@@ -145,11 +145,11 @@ impl<T: ?Sized> OperationVc<T> {
     /// consistent][crate::ReadConsistency::Strong] read of the value.
     ///
     /// This ensures that all internal tasks are finished before the read is returned.
-    pub async fn read_trait_strongly_consistent(self) -> Result<TraitRef<T>>
+    pub fn read_trait_strongly_consistent(self) -> ReadVcFuture<T, VcValueTraitCast<T>>
     where
         T: VcValueTrait,
     {
-        self.connect().into_trait_ref().strongly_consistent().await
+        self.connect().into_trait_ref().strongly_consistent()
     }
 }
 

filename: turbopack/crates/turbo-tasks/src/vc/read.rs
patch: @@ -161,7 +161,7 @@ where
     Cast: VcCast,
 {
     /// Do not use this: Use [`OperationVc::read_strongly_consistent`] instead.
-    pub fn strongly_consistent(mut self) -> Self {
+    pub(crate) fn strongly_consistent(mut self) -> Self {
         self.raw = self.raw.strongly_consistent();
         self
     }