Skip to content

Commit 86a1e41

Browse files
committed
Respect VcCellMode in TraitRef::cell
1 parent ef8e4e5 commit 86a1e41

File tree

2 files changed

+155
-8
lines changed

2 files changed

+155
-8
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#![feature(arbitrary_self_types)]
2+
3+
use anyhow::Result;
4+
use turbo_tasks::{IntoTraitRef, State, TraitRef, Upcast, Vc};
5+
use turbo_tasks_testing::{register, run, Registration};
6+
7+
static REGISTRATION: Registration = register!();
8+
9+
// Test that with `cell = "shared"`, the cell will be re-used as long as the
10+
// value is equal.
11+
#[tokio::test]
12+
async fn test_trait_ref_shared_cell_mode() {
13+
run(&REGISTRATION, async {
14+
let input = CellIdSelector {
15+
value: 42,
16+
cell_idx: State::new(0),
17+
}
18+
.cell();
19+
20+
// create the task and compute it
21+
let counter_value_vc = shared_value_from_input(input);
22+
let trait_ref_a = counter_value_vc.into_trait_ref().await.unwrap();
23+
24+
// invalidate the task, and pick a different cell id for the next execution
25+
input.await.unwrap().cell_idx.set_unconditionally(1);
26+
27+
// recompute the task
28+
let trait_ref_b = counter_value_vc.into_trait_ref().await.unwrap();
29+
30+
for trait_ref in [&trait_ref_a, &trait_ref_b] {
31+
assert_eq!(
32+
*TraitRef::cell(trait_ref.clone()).get_value().await.unwrap(),
33+
42
34+
);
35+
}
36+
37+
// because we're using `cell = "shared"`, these trait refs must use the same
38+
// underlying Arc/SharedRef (by identity)
39+
assert!(TraitRef::ptr_eq(&trait_ref_a, &trait_ref_b));
40+
})
41+
.await
42+
}
43+
44+
// Test that with `cell = "new"`, the cell will is never re-used, even if the
45+
// value is equal.
46+
#[tokio::test]
47+
async fn test_trait_ref_new_cell_mode() {
48+
run(&REGISTRATION, async {
49+
let input = CellIdSelector {
50+
value: 42,
51+
cell_idx: State::new(0),
52+
}
53+
.cell();
54+
55+
// create the task and compute it
56+
let counter_value_vc = new_value_from_input(input);
57+
let trait_ref_a = counter_value_vc.into_trait_ref().await.unwrap();
58+
59+
// invalidate the task, and pick a different cell id for the next execution
60+
input.await.unwrap().cell_idx.set_unconditionally(1);
61+
62+
// recompute the task
63+
let trait_ref_b = counter_value_vc.into_trait_ref().await.unwrap();
64+
65+
for trait_ref in [&trait_ref_a, &trait_ref_b] {
66+
assert_eq!(
67+
*TraitRef::cell(trait_ref.clone()).get_value().await.unwrap(),
68+
42
69+
);
70+
}
71+
72+
// because we're using `cell = "new"`, these trait refs must use different
73+
// underlying Arc/SharedRefs (by identity)
74+
assert!(!TraitRef::ptr_eq(&trait_ref_a, &trait_ref_b));
75+
})
76+
.await
77+
}
78+
79+
#[turbo_tasks::value_trait]
80+
trait ValueTrait {
81+
fn get_value(&self) -> Vc<usize>;
82+
}
83+
84+
#[turbo_tasks::value(transparent, cell = "shared")]
85+
struct SharedValue(usize);
86+
87+
#[turbo_tasks::value(transparent, cell = "new")]
88+
struct NewValue(usize);
89+
90+
#[turbo_tasks::value_impl]
91+
impl ValueTrait for SharedValue {
92+
#[turbo_tasks::function]
93+
fn get_value(&self) -> Vc<usize> {
94+
Vc::cell(self.0)
95+
}
96+
}
97+
98+
#[turbo_tasks::value_impl]
99+
impl ValueTrait for NewValue {
100+
#[turbo_tasks::function]
101+
fn get_value(&self) -> Vc<usize> {
102+
Vc::cell(self.0)
103+
}
104+
}
105+
106+
#[turbo_tasks::value]
107+
struct CellIdSelector {
108+
value: usize,
109+
cell_idx: State<usize>,
110+
}
111+
112+
async fn value_from_input<T>(
113+
input: Vc<CellIdSelector>,
114+
mut cell_fn: impl FnMut(usize) -> Vc<T>,
115+
) -> Result<Vc<Box<dyn ValueTrait>>>
116+
where
117+
T: ValueTrait + Upcast<Box<dyn ValueTrait>>,
118+
{
119+
let input = input.await?;
120+
121+
// create multiple cells so that we can pick from them, simulating a function
122+
// with non-deterministic ordering that returns a "random" cell that happens to
123+
// contain the same value
124+
let mut upcast_vcs = Vec::new();
125+
for _idx in 0..2 {
126+
upcast_vcs.push(Vc::upcast((cell_fn)(input.value)));
127+
}
128+
129+
// pick a different cell idx upon each invalidation/execution
130+
let picked_vc = upcast_vcs[*input.cell_idx.get()];
131+
132+
// round-trip through `TraitRef::cell`
133+
Ok(TraitRef::cell(picked_vc.into_trait_ref().await?))
134+
}
135+
136+
#[turbo_tasks::function]
137+
async fn shared_value_from_input(input: Vc<CellIdSelector>) -> Result<Vc<Box<dyn ValueTrait>>> {
138+
value_from_input::<SharedValue>(input, Vc::<SharedValue>::cell).await
139+
}
140+
141+
#[turbo_tasks::function]
142+
async fn new_value_from_input(input: Vc<CellIdSelector>) -> Result<Vc<Box<dyn ValueTrait>>> {
143+
value_from_input::<NewValue>(input, Vc::<NewValue>::cell).await
144+
}

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ use anyhow::Result;
44
use serde::{Deserialize, Serialize};
55

66
use crate::{
7-
manager::find_cell_by_type,
7+
registry::get_value_type,
88
task::shared_reference::TypedSharedReference,
99
vc::{cast::VcCast, ReadVcFuture, VcValueTraitCast},
10-
RawVc, Vc, VcValueTrait,
10+
Vc, VcValueTrait,
1111
};
1212

1313
/// Similar to a [`ReadRef<T>`][crate::ReadRef], but contains a value trait
@@ -90,6 +90,10 @@ where
9090
_t: PhantomData,
9191
}
9292
}
93+
94+
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
95+
triomphe::Arc::ptr_eq(&this.shared_reference.1 .0, &other.shared_reference.1 .0)
96+
}
9397
}
9498

9599
impl<T> TraitRef<T>
@@ -99,12 +103,11 @@ where
99103
/// Returns a new cell that points to a value that implements the value
100104
/// trait `T`.
101105
pub fn cell(trait_ref: TraitRef<T>) -> Vc<T> {
102-
// See Safety clause above.
103-
let TypedSharedReference(ty, shared_ref) = trait_ref.shared_reference;
104-
let local_cell = find_cell_by_type(ty);
105-
local_cell.update_with_shared_reference(shared_ref);
106-
let raw_vc: RawVc = local_cell.into();
107-
raw_vc.into()
106+
let TraitRef {
107+
shared_reference, ..
108+
} = trait_ref;
109+
let value_type = get_value_type(shared_reference.0);
110+
(value_type.raw_cell)(shared_reference).into()
108111
}
109112
}
110113

0 commit comments

Comments
 (0)