Skip to content

Commit

Permalink
Add support for #[turbo_tasks::value(resolved)] and `#[turbo_tasks:…
Browse files Browse the repository at this point in the history
…:value_trait(resolved)]` (vercel/turborepo#8720)

### Description

- `#[turbo_tasks::value(resolved)]`: This is essentially just shorthand for also doing `#[derive(ResolvedValue)]`. We'll want this on-by-default eventually, but it's strictly opt-in for now.
- `#[turbo_tasks::value_trait(resolved)]`: This adds an additional supertrait for `ResolvedValue`. This wasn't quite possible to do without this flag as most supertraits are required to implement `VcValueTrait` because they're used with the `Upcast`/`Downcast` traits.

### Testing Instructions

```
TRYBUILD=overwrite cargo nextest r -p turbo-tasks-macros-tests
```
  • Loading branch information
bgw authored Jul 11, 2024
1 parent 5af68d6 commit bc8119a
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 16 deletions.
14 changes: 13 additions & 1 deletion crates/turbo-tasks-macros-shared/src/value_trait_arguments.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use proc_macro2::Span;
use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
Meta, Token,
};

Expand All @@ -10,11 +12,18 @@ pub struct ValueTraitArguments {
/// Whether the macro should generate a `ValueDebug`-like `dbg()`
/// implementation on the trait's `Vc`.
pub debug: bool,
/// Should the trait have a `turbo_tasks::ResolvedValue` constraint?
///
/// `Some(...)` if enabled, containing the span that enabled the constraint.
pub resolved: Option<Span>,
}

impl Default for ValueTraitArguments {
fn default() -> Self {
Self { debug: true }
Self {
debug: true,
resolved: None,
}
}
}

Expand All @@ -31,6 +40,9 @@ impl Parse for ValueTraitArguments {
Some("no_debug") => {
result.debug = false;
}
Some("resolved") => {
result.resolved = Some(meta.span());
}
_ => {
return Err(syn::Error::new_spanned(meta, "unknown parameter"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Vc<i32>: ResolvedValue` is not satisfied
--> tests/derive_resolved_value/fail_contains_vc_inside_generic.rs:7:8
|
7 | a: Option<Box<[Vc<i32>; 4]>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ResolvedValue` is not implemented for `Vc<i32>`, which is required by `Option<Box<[Vc<i32>; 4]>>: ResolvedValue`
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ResolvedValue` is not implemented for `Vc<i32>`, which is required by `std::option::Option<Box<[Vc<i32>; 4]>>: ResolvedValue`
|
= help: the following other types implement trait `ResolvedValue`:
&T
Expand All @@ -16,7 +16,7 @@ error[E0277]: the trait bound `Vc<i32>: ResolvedValue` is not satisfied
and $N others
= note: required for `[Vc<i32>; 4]` to implement `ResolvedValue`
= note: 2 redundant requirements hidden
= note: required for `Option<Box<[Vc<i32>; 4]>>` to implement `ResolvedValue`
= note: required for `std::option::Option<Box<[Vc<i32>; 4]>>` to implement `ResolvedValue`
note: required by a bound in `DeriveResolvedValueAssertion::assert_impl_resolved_value`
--> tests/derive_resolved_value/fail_contains_vc_inside_generic.rs:5:10
|
Expand Down
14 changes: 14 additions & 0 deletions crates/turbo-tasks-macros-tests/tests/trybuild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,17 @@ fn derive_resolved_value() {
t.pass("tests/derive_resolved_value/pass_*.rs");
t.compile_fail("tests/derive_resolved_value/fail_*.rs");
}

#[test]
fn value() {
let t = trybuild::TestCases::new();
t.pass("tests/value/pass_*.rs");
t.compile_fail("tests/value/fail_*.rs");
}

#[test]
fn value_trait() {
let t = trybuild::TestCases::new();
t.pass("tests/value_trait/pass_*.rs");
t.compile_fail("tests/value_trait/fail_*.rs");
}
13 changes: 13 additions & 0 deletions crates/turbo-tasks-macros-tests/tests/value/fail_resolved.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![feature(arbitrary_self_types)]

use turbo_tasks::Vc;

#[turbo_tasks::value(resolved)]
struct MyValue {
value: Vc<i32>,
}

fn main() {
let v = MyValue { value: Vc::cell(0) };
let _ = v.value;
}
22 changes: 22 additions & 0 deletions crates/turbo-tasks-macros-tests/tests/value/fail_resolved.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
error[E0277]: the trait bound `Vc<i32>: ResolvedValue` is not satisfied
--> tests/value/fail_resolved.rs:7:12
|
7 | value: Vc<i32>,
| ^^^^^^^ the trait `ResolvedValue` is not implemented for `Vc<i32>`
|
= help: the following other types implement trait `ResolvedValue`:
&T
&mut T
()
(A, Z, Y, X, W, V, U, T)
(B, A, Z, Y, X, W, V, U, T)
(C, B, A, Z, Y, X, W, V, U, T)
(D, C, B, A, Z, Y, X, W, V, U, T)
(E, D, C, B, A, Z, Y, X, W, V, U, T)
and $N others
note: required by a bound in `DeriveResolvedValueAssertion::assert_impl_resolved_value`
--> tests/value/fail_resolved.rs:5:22
|
5 | #[turbo_tasks::value(resolved)]
| ^^^^^^^^ required by this bound in `DeriveResolvedValueAssertion::assert_impl_resolved_value`
= note: this error originates in the derive macro `turbo_tasks::ResolvedValue` (in Nightly builds, run with -Z macro-backtrace for more info)
14 changes: 14 additions & 0 deletions crates/turbo-tasks-macros-tests/tests/value/pass_resolved.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![feature(arbitrary_self_types)]

#[turbo_tasks::value(resolved)]
struct MyValue {
value: i32,
}

fn expects_resolved<T: turbo_tasks::ResolvedValue>(value: T) {}

fn main() {
let v = MyValue { value: 0 };
expects_resolved(v);
let _ = v.value;
}
10 changes: 10 additions & 0 deletions crates/turbo-tasks-macros-tests/tests/value_trait/pass_resolved.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![feature(arbitrary_self_types)]

#[turbo_tasks::value_trait(resolved)]
trait MyTrait {}

fn expects_resolved<T: turbo_tasks::ResolvedValue + ?Sized>() {}

fn main() {
expects_resolved::<&dyn MyTrait>();
}
6 changes: 4 additions & 2 deletions crates/turbo-tasks-macros/src/derive/resolved_value_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub fn derive_resolved_value(input: TokenStream) -> TokenStream {

let (impl_generics, ty_generics, where_clause) = derive_input.generics.split_for_impl();
quote! {
unsafe impl #impl_generics ::turbo_tasks::ResolvedValue
unsafe impl #impl_generics turbo_tasks::ResolvedValue
for #ident #ty_generics #where_clause {}
#assertions
}
Expand Down Expand Up @@ -47,7 +47,9 @@ fn assert_fields_impl_resolved_value(generics: &Generics, data: &Data) -> TokenS
struct DeriveResolvedValueAssertion #impl_generics (#(#field_types),*) #where_clause;

impl #impl_generics DeriveResolvedValueAssertion #ty_generics #where_clause {
fn assert_impl_resolved_value<ExpectedResolvedValue: ResolvedValue + ?Sized>() {}
fn assert_impl_resolved_value<
ExpectedResolvedValue: turbo_tasks::ResolvedValue + ?Sized
>() {}
fn field_types() {
#(#assertion_calls)*
}
Expand Down
1 change: 0 additions & 1 deletion crates/turbo-tasks-macros/src/derive/value_macro.rs

This file was deleted.

25 changes: 25 additions & 0 deletions crates/turbo-tasks-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ pub fn derive_task_input(input: TokenStream) -> TokenStream {
///
/// Example: `#[turbo_tasks::value(transparent)]`
///
/// ### `resolved`
///
/// A shorthand syntax for
/// [`#[derive(turbo_tasks::ResolvedValue)]`][macro@turbo_tasks::ResolvedValue]
///
/// Example: `#[turbo_tasks::value(resolved)]`
///
/// TODO: add more documentation: presets, traits
#[allow_internal_unstable(min_specialization, into_future, trivial_bounds)]
#[proc_macro_error]
Expand All @@ -127,6 +134,24 @@ pub fn value(args: TokenStream, input: TokenStream) -> TokenStream {
value_macro::value(args, input)
}

/// Allows this trait to be used as part of a trait object inside of a value
/// cell, in the form of `Vc<dyn MyTrait>`.
///
/// ## Arguments
///
/// Example: `#[turbo_tasks::value_trait(no_debug, resolved)]`
///
/// ### 'no_debug`
///
/// Disables the automatic implementation of [`turbo_tasks::debug::ValueDebug`].
///
/// Example: `#[turbo_tasks::value_trait(no_debug)]`
///
/// ### 'resolved`
///
/// Adds [`turbo_tasks::ResolvedValue`] as a supertrait of this trait.
///
/// Example: `#[turbo_tasks::value_trait(resolved)]`
#[allow_internal_unstable(min_specialization, into_future, trivial_bounds)]
#[proc_macro_error]
#[proc_macro_attribute]
Expand Down
36 changes: 31 additions & 5 deletions crates/turbo-tasks-macros/src/value_macro.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::sync::OnceLock;

use proc_macro::TokenStream;
use proc_macro2::Ident;
use quote::{quote, ToTokens};
use proc_macro2::{Ident, Span};
use quote::{quote, quote_spanned, ToTokens};
use regex::Regex;
use syn::{
parse::{Parse, ParseStream},
Expand Down Expand Up @@ -110,6 +110,10 @@ struct ValueArguments {
cell_mode: CellMode,
manual_eq: bool,
transparent: bool,
/// Should we `#[derive(turbo_tasks::ResolvedValue)]`?
///
/// `Some(...)` if enabled, containing the span that enabled the derive.
resolved: Option<Span>,
}

impl Parse for ValueArguments {
Expand All @@ -119,6 +123,7 @@ impl Parse for ValueArguments {
into_mode: IntoMode::None,
cell_mode: CellMode::Shared,
manual_eq: false,
resolved: None,
transparent: false,
};
let punctuated: Punctuated<Meta, Token![,]> = input.parse_terminated(Meta::parse)?;
Expand Down Expand Up @@ -174,6 +179,9 @@ impl Parse for ValueArguments {
("transparent", Meta::Path(_)) => {
result.transparent = true;
}
("resolved", Meta::Path(path)) => {
result.resolved = Some(path.span());
}
(_, meta) => {
return Err(Error::new_spanned(
&meta,
Expand All @@ -199,6 +207,7 @@ pub fn value(args: TokenStream, input: TokenStream) -> TokenStream {
cell_mode,
manual_eq,
transparent,
resolved,
} = parse_macro_input!(args as ValueArguments);

let mut inner_type = None;
Expand Down Expand Up @@ -328,7 +337,12 @@ pub fn value(args: TokenStream, input: TokenStream) -> TokenStream {
}
}
SerializationMode::Auto | SerializationMode::AutoForInput => quote! {
#[derive(turbo_tasks::trace::TraceRawVcs, serde::Serialize, serde::Deserialize)]
#[derive(
turbo_tasks::trace::TraceRawVcs,
turbo_tasks::macro_helpers::serde::Serialize,
turbo_tasks::macro_helpers::serde::Deserialize,
)]
#[serde(crate = "turbo_tasks::macro_helpers::serde")]
},
};
let debug_derive = if inner_type.is_some() {
Expand All @@ -338,7 +352,10 @@ pub fn value(args: TokenStream, input: TokenStream) -> TokenStream {
}
} else {
quote! {
#[derive(turbo_tasks::debug::ValueDebugFormat, turbo_tasks::debug::internal::ValueDebug)]
#[derive(
turbo_tasks::debug::ValueDebugFormat,
turbo_tasks::debug::internal::ValueDebug,
)]
}
};
let eq_derive = if manual_eq {
Expand All @@ -348,6 +365,14 @@ pub fn value(args: TokenStream, input: TokenStream) -> TokenStream {
#[derive(PartialEq, Eq)]
)
};
let resolved_derive = if let Some(span) = resolved {
quote_spanned!(
span =>
#[derive(turbo_tasks::ResolvedValue)]
)
} else {
quote!()
};

let new_value_type = match serialization_mode {
SerializationMode::None => quote! {
Expand Down Expand Up @@ -406,8 +431,9 @@ pub fn value(args: TokenStream, input: TokenStream) -> TokenStream {

let expanded = quote! {
#derive
#eq_derive
#debug_derive
#eq_derive
#resolved_derive
#item

impl #ident {
Expand Down
18 changes: 13 additions & 5 deletions crates/turbo-tasks-macros/src/value_trait_macro.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use proc_macro::TokenStream;
use proc_macro2::{Ident, TokenStream as TokenStream2};
use quote::quote;
use quote::{quote, quote_spanned};
use syn::{
parse_macro_input, parse_quote, spanned::Spanned, ExprPath, ItemTrait, TraitItem,
TraitItemMethod,
Expand All @@ -13,7 +13,7 @@ use turbo_tasks_macros_shared::{
use crate::func::{DefinitionContext, NativeFn, TurboFn};

pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
let ValueTraitArguments { debug } = parse_macro_input!(args as ValueTraitArguments);
let ValueTraitArguments { debug, resolved } = parse_macro_input!(args as ValueTraitArguments);

let item = parse_macro_input!(input as ItemTrait);

Expand Down Expand Up @@ -59,7 +59,7 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
.emit();
}

let supertraits = supertraits.into_iter().collect::<Vec<_>>();
let supertraits = supertraits.iter().collect::<Vec<_>>();

let trait_type_ident = get_trait_type_ident(trait_ident);
let trait_type_id_ident = get_trait_type_id_ident(trait_ident);
Expand Down Expand Up @@ -194,10 +194,18 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
quote! {}
};

let mut extended_supertraits = Vec::new();
if let Some(span) = resolved {
extended_supertraits.push(quote_spanned! {
span => turbo_tasks::ResolvedValue
});
}
extended_supertraits.push(quote!(::std::marker::Send));

let expanded = quote! {
#[must_use]
#(#attrs)*
#vis #trait_token #trait_ident: std::marker::Send + #(#supertraits)+*
#vis #trait_token #trait_ident: #(#supertraits +)* #(#extended_supertraits +)*
{
#(#items)*
}
Expand Down Expand Up @@ -230,7 +238,7 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {

impl<T> #trait_ident for T
where
T: turbo_tasks::Dynamic<Box<dyn #trait_ident>> #(+ #supertraits)*,
T: turbo_tasks::Dynamic<Box<dyn #trait_ident>> + #(#supertraits +)* #(#extended_supertraits +)*,
{
#(#dynamic_trait_fns)*
}
Expand Down
1 change: 1 addition & 0 deletions crates/turbo-tasks/src/macro_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Runtime helpers for [turbo-tasks-macro].
pub use once_cell::sync::{Lazy, OnceCell};
pub use serde;
pub use tracing;

pub use super::manager::{find_cell_by_type, notify_scheduled_tasks, spawn_detached};
Expand Down

0 comments on commit bc8119a

Please sign in to comment.