-
Notifications
You must be signed in to change notification settings - Fork 27.2k
Commit
…ce a macro annotation for creating OperationVc types (#72871) Introduces a new `operation` argument to the `#[turbo_tasks::function]` macro for creating functions that return `OperationVc`: ``` // this function's external signature returns an `OperationVc` #[turbo_tasks::function(operation)] async fn multiply(value: OperationVc<i32>, coefficient: i32) -> Result<Vc<i32>> { Ok(Vc::cell(*value.connect().await? * coefficient)) } ``` This is important to solve a few major footguns with manually-constructed `OperationVc`s: - It can be hard to know if a `Vc` is an operation or not, and the only warning you'd get if you got it wrong was a runtime error. - Local-task-based resolution (#69126) will implicitly create local `Vc`s if an argument isn't resolved. - ~We want to enforce that all arguments to `OperationVc`-returning functions are also `OperationVc`s or non-`Vc` values. Otherwise you could end up with a stale/wrong `OperationVc`.~ Scrapped, this was too hard/impractical, see below. This removes the public constructor. Methods are not currently supported because: 1. Operations are uncommon, and it's not worth the effort, IMO. 2. There's no way to make it work for dynamic-dispatched method calls, as we cannot resolve the type of `self`. It could be made to work for inherent impls and non-object trait types. --- This is basically implementing @sokra's TODO comment in the old `OperationVc::new` constructor: ``` // TODO to avoid this runtime check, we should mark functions with `(operation)` and return // a OperationVc directly ``` But with assertions for the function arguments, based on some discussion in DMs: <img src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/HAZVitxRNnZz8QMiPn4a/13952614-f421-4c8a-99b8-3ce5f19715ae.png" width="600"/> We allow *either* `ResolvedVc` or `OperationVc` as arguments because: - Only accepting `OperationVc` arguments was impossible to refactor to, as this made it "viral" and there are too many places where we need to use operations that have too many dependencies. - While it makes sense for `State` to require `OperationVc` as arguments to any operation (keeps the whole dependency/call tree alive), for collectibles, sometimes you want the arguments to be `ResolvedVc`. It's just a matter of if you want to include collectibles generated when creating the arguments or not.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../turbo-tasks-testing/tests/operation_vc.rs |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#![allow(dead_code)] | ||
#![feature(arbitrary_self_types)] | ||
#![feature(arbitrary_self_types_pointers)] | ||
|
||
use turbo_tasks::Vc; | ||
|
||
#[turbo_tasks::value] | ||
struct Foobar; | ||
|
||
#[turbo_tasks::value_impl] | ||
impl Foobar { | ||
#[turbo_tasks::function(operation)] | ||
fn self_ref(&self) -> Vc<()> { | ||
Vc::cell(()) | ||
} | ||
} | ||
|
||
fn main() {} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#![allow(dead_code)] | ||
#![feature(arbitrary_self_types)] | ||
#![feature(arbitrary_self_types_pointers)] | ||
|
||
use turbo_tasks::{OperationVc, Vc}; | ||
|
||
#[turbo_tasks::value] | ||
struct Foobar; | ||
|
||
#[turbo_tasks::value_impl] | ||
impl Foobar { | ||
#[turbo_tasks::function(operation)] | ||
fn arbitrary_self_type(self: OperationVc<Self>) -> Vc<()> { | ||
Vc::cell(()) | ||
} | ||
} | ||
|
||
fn main() {} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#![allow(dead_code)] | ||
#![feature(arbitrary_self_types)] | ||
#![feature(arbitrary_self_types_pointers)] | ||
|
||
use turbo_tasks::Vc; | ||
|
||
#[turbo_tasks::value] | ||
struct Foobar; | ||
|
||
#[turbo_tasks::value_impl] | ||
impl Foobar { | ||
#[turbo_tasks::function(operation)] | ||
fn arbitrary_self_type_base_vc(self: Vc<Self>) -> Vc<()> { | ||
Vc::cell(()) | ||
} | ||
} | ||
|
||
fn main() {} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#![allow(dead_code)] | ||
|
||
use anyhow::Result; | ||
use turbo_tasks::{ResolvedVc, Vc}; | ||
|
||
#[turbo_tasks::function(operation)] | ||
async fn multiply(value: Vc<i32>, coefficient: ResolvedVc<i32>) -> Result<Vc<i32>> { | ||
let value = *value.await?; | ||
let coefficient = *coefficient.await?; | ||
Ok(Vc::cell(value * coefficient)) | ||
} | ||
|
||
fn main() {} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use anyhow::Result; | ||
use turbo_tasks::{OperationVc, Vc}; | ||
|
||
#[turbo_tasks::function(operation)] | ||
fn bare_op_fn() -> Vc<i32> { | ||
Vc::cell(21) | ||
} | ||
|
||
#[turbo_tasks::function(operation)] | ||
async fn multiply(value: OperationVc<i32>, coefficient: i32) -> Result<Vc<i32>> { | ||
Ok(Vc::cell(*value.connect().await? * coefficient)) | ||
} | ||
|
||
#[allow(dead_code)] | ||
fn use_operations() { | ||
let twenty_one: OperationVc<i32> = bare_op_fn(); | ||
let _fourty_two: OperationVc<i32> = multiply(twenty_one, 2); | ||
} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
use anyhow::Result; | ||
use turbo_tasks::{OperationVc, ResolvedVc, Vc}; | ||
|
||
#[turbo_tasks::function(operation)] | ||
fn bare_op_fn() -> Vc<i32> { | ||
Vc::cell(21) | ||
} | ||
|
||
// operations can take `ResolvedVc`s too (anything that's a `NonLocalValue`). | ||
#[turbo_tasks::function(operation)] | ||
async fn multiply(value: OperationVc<i32>, coefficient: ResolvedVc<i32>) -> Result<Vc<i32>> { | ||
Ok(Vc::cell((*value.connect().await?) * (*coefficient.await?))) | ||
} | ||
|
||
#[allow(dead_code)] | ||
fn use_operations() { | ||
let twenty_one: OperationVc<i32> = bare_op_fn(); | ||
let _fourty_two: OperationVc<i32> = multiply(twenty_one, ResolvedVc::cell(2)); | ||
} | ||
|
||
fn main() {} |