Skip to content

Commit 026c5f8

Browse files
committed
refactor(turbo-tasks): Remove task id from RawVc::LocalOutput
1 parent f746ec3 commit 026c5f8

File tree

3 files changed

+85
-36
lines changed

3 files changed

+85
-36
lines changed

turbopack/crates/turbo-tasks-backend/src/backend/mod.rs

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,11 +1124,16 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
11241124
let task_name = task_type.get_name();
11251125

11261126
let cause_self = task_type.this.and_then(|cause_self_raw_vc| {
1127-
let task_id = cause_self_raw_vc.get_task_id();
1127+
let Some(task_id) = cause_self_raw_vc.try_get_task_id() else {
1128+
// `task_id` should never be `None` at this point, as that would imply a
1129+
// non-local task is returning a local `Vc`...
1130+
// Just ignore if it happens, as we're likely already panicking.
1131+
return None;
1132+
};
11281133
if task_id.is_transient() {
11291134
Some(Box::new(inner_id(
11301135
backend,
1131-
cause_self_raw_vc.get_task_id(),
1136+
task_id,
11321137
cause_self_raw_vc.try_get_type_id(),
11331138
visited_set,
11341139
)))
@@ -1140,8 +1145,16 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
11401145
.arg
11411146
.get_raw_vcs()
11421147
.into_iter()
1143-
.map(|raw_vc| (raw_vc.get_task_id(), raw_vc.try_get_type_id()))
1144-
.filter(|(task_id, _)| task_id.is_transient())
1148+
.filter_map(|raw_vc| {
1149+
let Some(task_id) = raw_vc.try_get_task_id() else {
1150+
// `task_id` should never be `None` (see comment above)
1151+
return None;
1152+
};
1153+
if task_id.is_transient() {
1154+
return None;
1155+
}
1156+
Some((task_id, raw_vc.try_get_type_id()))
1157+
})
11451158
.collect::<IndexSet<_>>() // dedupe
11461159
.into_iter()
11471160
.map(|(task_id, cell_type_id)| {
@@ -2184,24 +2197,25 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
21842197
// these checks occur in a potentially hot codepath, but they're cheap
21852198
let RawVc::TaskCell(col_task_id, col_cell_id) = collectible else {
21862199
// This should never happen: The collectible APIs use ResolvedVc
2187-
let task_info =
2188-
if let Some(col_task_ty) = self.lookup_task_type(collectible.get_task_id()) {
2189-
Cow::Owned(format!(" (return type of {})", col_task_ty))
2190-
} else {
2191-
Cow::Borrowed("")
2192-
};
2200+
let task_info = if let Some(col_task_ty) = collectible
2201+
.try_get_task_id()
2202+
.and_then(|t| self.lookup_task_type(t))
2203+
{
2204+
Cow::Owned(format!(" (return type of {col_task_ty})"))
2205+
} else {
2206+
Cow::Borrowed("")
2207+
};
21932208
panic!("Collectible{task_info} must be a ResolvedVc")
21942209
};
21952210
if col_task_id.is_transient() && !task_id.is_transient() {
2196-
let transient_reason =
2197-
if let Some(col_task_ty) = self.lookup_task_type(collectible.get_task_id()) {
2198-
Cow::Owned(format!(
2199-
". The collectible is transient because it depends on:\n{}",
2200-
self.debug_trace_transient_task(&col_task_ty, Some(col_cell_id)),
2201-
))
2202-
} else {
2203-
Cow::Borrowed("")
2204-
};
2211+
let transient_reason = if let Some(col_task_ty) = self.lookup_task_type(col_task_id) {
2212+
Cow::Owned(format!(
2213+
". The collectible is transient because it depends on:\n{}",
2214+
self.debug_trace_transient_task(&col_task_ty, Some(col_cell_id)),
2215+
))
2216+
} else {
2217+
Cow::Borrowed("")
2218+
};
22052219
// this should never happen: How would a persistent function get a transient Vc?
22062220
panic!(
22072221
"Collectible is transient, transient collectibles cannot be emitted from \

turbopack/crates/turbo-tasks/src/manager.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ use crate::{
4848
VcValueType,
4949
};
5050

51+
/// Common base trait for [`TurboTasksApi`] and [`TurboTasksBackendApi`]. Provides APIs for creating
52+
/// tasks from function calls.
5153
pub trait TurboTasksCallApi: Sync + Send {
5254
/// Calls a native function with arguments. Resolves arguments when needed
5355
/// with a wrapper task.
@@ -93,6 +95,11 @@ pub trait TurboTasksCallApi: Sync + Send {
9395
) -> TaskId;
9496
}
9597

98+
/// A type-erased subset of [`TurboTasks`] stored inside a thread local when we're in a turbo task
99+
/// context. Returned by the [`turbo_tasks`] helper function.
100+
///
101+
/// This trait is needed because thread locals cannot contain an unresolved [`Backend`] type
102+
/// parameter.
96103
pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send {
97104
fn pin(&self) -> Arc<dyn TurboTasksApi>;
98105

@@ -135,9 +142,20 @@ pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send {
135142
options: ReadCellOptions,
136143
) -> Result<Result<TypedCellContent, EventListener>>;
137144

145+
/// Reads a [`RawVc::LocalOutput`]. If the task has completed, returns the [`RawVc`] the local
146+
/// task points to.
147+
///
148+
/// The returned [`RawVc`] may also be a [`RawVc::LocalOutput`], so this may need to be called
149+
/// recursively or in a loop.
150+
///
138151
/// This does not accept a consistency argument, as you cannot control consistency of a read of
139152
/// an operation owned by your own task. Strongly consistent reads are only allowed on
140-
/// `OperationVc`s, which should never be local tasks.
153+
/// [`OperationVc`]s, which should never be local tasks.
154+
///
155+
/// No dependency tracking will happen as a result of this function call, as it's a no-op for a
156+
/// task to depend on itself.
157+
///
158+
/// [`OperationVc`]: crate::OperationVc
141159
fn try_read_local_output(
142160
&self,
143161
execution_id: ExecutionId,
@@ -216,6 +234,7 @@ impl<T> Unused<T> {
216234
}
217235
}
218236

237+
/// A subset of the [`TurboTasks`] API that's exposed to [`Backend`] implementations.
219238
pub trait TurboTasksBackendApi<B: Backend + 'static>: TurboTasksCallApi + Sync + Send {
220239
fn pin(&self) -> Arc<dyn TurboTasksBackendApi<B>>;
221240

@@ -265,8 +284,8 @@ pub trait TurboTasksBackendApi<B: Backend + 'static>: TurboTasksCallApi + Sync +
265284
fn backend(&self) -> &B;
266285
}
267286

268-
/// An extension trait for methods of `TurboTasksBackendApi` that are not object-safe. This is
269-
/// automatically implemented for all `TurboTasksBackendApi`s using a blanket impl.
287+
/// An extension trait for methods of [`TurboTasksBackendApi`] that are not object-safe. This is
288+
/// automatically implemented for all [`TurboTasksBackendApi`]s using a blanket impl.
270289
pub trait TurboTasksBackendApiExt<B: Backend + 'static>: TurboTasksBackendApi<B> {
271290
/// Allows modification of the [`Backend::TaskState`].
272291
///
@@ -768,6 +787,8 @@ impl<B: Backend + 'static> TurboTasks<B> {
768787
self.backend.get_task_description(parent_task_id),
769788
ty,
770789
);
790+
#[cfg(not(feature = "tokio_tracing"))]
791+
let _ = parent_task_id; // suppress unused variable warning
771792

772793
let this = self.pin();
773794
let future = async move {
@@ -822,7 +843,7 @@ impl<B: Backend + 'static> TurboTasks<B> {
822843
#[cfg(not(feature = "tokio_tracing"))]
823844
tokio::task::spawn(future);
824845

825-
RawVc::LocalOutput(parent_task_id, persistence, execution_id, local_task_id)
846+
RawVc::LocalOutput(persistence, execution_id, local_task_id)
826847
}
827848

828849
fn begin_primary_job(&self) {

turbopack/crates/turbo-tasks/src/raw_vc.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl Display for CellId {
5757
pub enum RawVc {
5858
TaskOutput(TaskId),
5959
TaskCell(TaskId, CellId),
60-
LocalOutput(TaskId, TaskPersistence, ExecutionId, LocalTaskId),
60+
LocalOutput(TaskPersistence, ExecutionId, LocalTaskId),
6161
}
6262

6363
impl RawVc {
@@ -84,7 +84,7 @@ impl RawVc {
8484
pub fn is_transient(&self) -> bool {
8585
match self {
8686
RawVc::TaskOutput(task) | RawVc::TaskCell(task, ..) => task.is_transient(),
87-
RawVc::LocalOutput(_, persistence, ..) => *persistence == TaskPersistence::Transient,
87+
RawVc::LocalOutput(persistence, ..) => *persistence == TaskPersistence::Transient,
8888
}
8989
}
9090

@@ -148,7 +148,7 @@ impl RawVc {
148148
return Err(ResolveTypeError::NoContent);
149149
}
150150
}
151-
RawVc::LocalOutput(_task_id, _persistence, execution_id, local_task_id) => {
151+
RawVc::LocalOutput(_persistence, execution_id, local_task_id) => {
152152
current = read_local_output(&*tt, execution_id, local_task_id)
153153
.await
154154
.map_err(|source| ResolveTypeError::TaskError { source })?;
@@ -185,7 +185,7 @@ impl RawVc {
185185
consistency = ReadConsistency::Eventual;
186186
}
187187
RawVc::TaskCell(_, _) => return Ok(current),
188-
RawVc::LocalOutput(_task_id, _persistence, execution_id, local_task_id) => {
188+
RawVc::LocalOutput(_persistence, execution_id, local_task_id) => {
189189
debug_assert_eq!(consistency, ReadConsistency::Eventual);
190190
current = read_local_output(&*tt, execution_id, local_task_id).await?;
191191
}
@@ -200,7 +200,7 @@ impl RawVc {
200200
let mut current = self;
201201
loop {
202202
match current {
203-
RawVc::LocalOutput(_task_id, _persistence, execution_id, local_task_id) => {
203+
RawVc::LocalOutput(_persistence, execution_id, local_task_id) => {
204204
current = read_local_output(&*tt, execution_id, local_task_id).await?;
205205
}
206206
non_local => return Ok(non_local),
@@ -209,13 +209,17 @@ impl RawVc {
209209
}
210210

211211
pub(crate) fn connect(&self) {
212+
let RawVc::TaskOutput(task_id) = self else {
213+
panic!("RawVc::connect() must only be called on a RawVc::TaskOutput");
214+
};
212215
let tt = turbo_tasks();
213-
tt.connect_task(self.get_task_id());
216+
tt.connect_task(*task_id);
214217
}
215218

216-
pub fn get_task_id(&self) -> TaskId {
219+
pub fn try_get_task_id(&self) -> Option<TaskId> {
217220
match self {
218-
RawVc::TaskOutput(t) | RawVc::TaskCell(t, ..) | RawVc::LocalOutput(t, ..) => *t,
221+
RawVc::TaskOutput(t) | RawVc::TaskCell(t, ..) => Some(*t),
222+
RawVc::LocalOutput(..) => None,
219223
}
220224
}
221225

@@ -250,20 +254,30 @@ impl RawVc {
250254
/// This implementation of `CollectiblesSource` assumes that `self` is a `RawVc::TaskOutput`.
251255
impl CollectiblesSource for RawVc {
252256
fn peek_collectibles<T: VcValueTrait + ?Sized>(self) -> AutoSet<ResolvedVc<T>> {
253-
debug_assert!(matches!(self, RawVc::TaskOutput(..)));
257+
let RawVc::TaskOutput(task_id) = self else {
258+
panic!(
259+
"<RawVc as CollectiblesSource>::peek_collectibles() must only be called on a \
260+
RawVc::TaskOutput"
261+
);
262+
};
254263
let tt = turbo_tasks();
255264
tt.notify_scheduled_tasks();
256-
let map = tt.read_task_collectibles(self.get_task_id(), T::get_trait_type_id());
265+
let map = tt.read_task_collectibles(task_id, T::get_trait_type_id());
257266
map.into_iter()
258267
.filter_map(|(raw, count)| (count > 0).then_some(raw.try_into().unwrap()))
259268
.collect()
260269
}
261270

262271
fn take_collectibles<T: VcValueTrait + ?Sized>(self) -> AutoSet<ResolvedVc<T>> {
263-
debug_assert!(matches!(self, RawVc::TaskOutput(..)));
272+
let RawVc::TaskOutput(task_id) = self else {
273+
panic!(
274+
"<RawVc as CollectiblesSource>::take_collectibles() must only be called on a \
275+
RawVc::TaskOutput"
276+
);
277+
};
264278
let tt = turbo_tasks();
265279
tt.notify_scheduled_tasks();
266-
let map = tt.read_task_collectibles(self.get_task_id(), T::get_trait_type_id());
280+
let map = tt.read_task_collectibles(task_id, T::get_trait_type_id());
267281
tt.unemit_collectibles(T::get_trait_type_id(), &map);
268282
map.into_iter()
269283
.filter_map(|(raw, count)| (count > 0).then_some(raw.try_into().unwrap()))
@@ -360,7 +374,7 @@ impl Future for ReadRawVcFuture {
360374
Err(err) => return Poll::Ready(Err(err)),
361375
}
362376
}
363-
RawVc::LocalOutput(_task_id, _persistence, execution_id, local_output_id) => {
377+
RawVc::LocalOutput(_persistence, execution_id, local_output_id) => {
364378
debug_assert_eq!(this.consistency, ReadConsistency::Eventual);
365379
let read_result = tt.try_read_local_output(execution_id, local_output_id);
366380
match read_result {

0 commit comments

Comments
 (0)