Skip to content

Commit f9de66e

Browse files
authored
[turbopack] Drop turbo_tasks::function from EcmascriptAnalyzable::module_content (#83277)
This function simply plugs two other VCs together, and it never gets a cache hit because it is "dominated" by other tasks. The only reason it is a turbotask is because it is defined as a trait item, however, we recently (#79217) allowed for value_trait items to not be turbo tasks. This PR builds on that to additionally allow for non-turbo_task trait items to accept `Vc<Self>`. This only really works if there is also a default implementation which works for this case. A tiny speed up progression in production ![image.png](https://app.graphite.dev/user-attachments/assets/c6d82929-5fb2-4921-b566-d648751a00ee.png)
1 parent 438606c commit f9de66e

File tree

7 files changed

+109
-54
lines changed

7 files changed

+109
-54
lines changed

turbopack/crates/turbo-tasks-macros/src/func.rs

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -108,46 +108,8 @@ impl TurboFn<'_> {
108108
_ => &definition_context,
109109
};
110110

111-
match self_type.as_ref() {
112-
// we allow `&Self` but not `&mut Self`
113-
syn::Type::Reference(type_reference) => {
114-
if let Some(m) = type_reference.mutability {
115-
m.span()
116-
.unwrap()
117-
.error(format!(
118-
"{} cannot take self by mutable reference, use &self or \
119-
self: Vc<Self> instead",
120-
definition_context.function_type(),
121-
))
122-
.emit();
123-
return None;
124-
}
125-
126-
match type_reference.elem.as_ref() {
127-
syn::Type::Path(TypePath { qself: None, path })
128-
if path.is_ident("Self") => {}
129-
_ => {
130-
self_type
131-
.span()
132-
.unwrap()
133-
.error(
134-
"Unexpected `self` type, use `&self` or `self: \
135-
Vc<Self>",
136-
)
137-
.emit();
138-
return None;
139-
}
140-
}
141-
}
142-
syn::Type::Path(_) => {}
143-
_ => {
144-
self_type
145-
.span()
146-
.unwrap()
147-
.error("Unexpected `self` type, use `&self` or `self: Vc<Self>")
148-
.emit();
149-
return None;
150-
}
111+
if get_receiver_style(self_type, definition_context) == ReceiverStyle::Error {
112+
return None;
151113
}
152114
// We don't validate that the user provided a valid `turbo_tasks::Vc<Self>`
153115
// here. We'll rely on the compiler to emit an error if the user provided an
@@ -695,6 +657,62 @@ impl TurboFn<'_> {
695657
}
696658
}
697659

660+
#[derive(PartialEq, Eq)]
661+
pub enum ReceiverStyle {
662+
// A reference like &self or self: &Self
663+
Reference,
664+
// A Vc<> type, this is optimistic
665+
Vc,
666+
Error,
667+
}
668+
669+
pub(crate) fn get_receiver_style(
670+
self_type: &Type,
671+
definition_context: &DefinitionContext,
672+
) -> ReceiverStyle {
673+
match self_type {
674+
// we allow `&Self` but not `&mut Self`
675+
syn::Type::Reference(type_reference) => {
676+
if let Some(m) = type_reference.mutability {
677+
m.span()
678+
.unwrap()
679+
.error(format!(
680+
"{} cannot take self by mutable reference, use &self or self: Vc<Self> \
681+
instead",
682+
definition_context.function_type(),
683+
))
684+
.emit();
685+
return ReceiverStyle::Error;
686+
}
687+
688+
match type_reference.elem.as_ref() {
689+
syn::Type::Path(TypePath { qself: None, path }) if path.is_ident("Self") => {}
690+
_ => {
691+
self_type
692+
.span()
693+
.unwrap()
694+
.error("Unexpected `self` type, use `&self` or `self: Vc<Self>")
695+
.emit();
696+
return ReceiverStyle::Error;
697+
}
698+
}
699+
return ReceiverStyle::Reference;
700+
}
701+
syn::Type::Path(_) => {}
702+
_ => {
703+
self_type
704+
.span()
705+
.unwrap()
706+
.error("Unexpected `self` type, use `&self` or `self: Vc<Self>")
707+
.emit();
708+
return ReceiverStyle::Error;
709+
}
710+
}
711+
// All other cases are assumed to be a VC, this is not guaranteed but we are happy to just have
712+
// compiler errors when this assumption is wrong.
713+
ReceiverStyle::Vc
714+
}
715+
698716
/// An indication of what kind of IO this function does. Currently only used for
699717
/// static analysis, and ignored within this macro.
700718
#[derive(Hash, PartialEq, Eq)]

turbopack/crates/turbo-tasks-macros/src/value_trait_macro.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use proc_macro::TokenStream;
22
use proc_macro2::{Ident, TokenStream as TokenStream2};
33
use quote::{quote, quote_spanned};
44
use syn::{
5-
FnArg, ItemTrait, Pat, TraitItem, TraitItemFn, parse_macro_input, parse_quote, spanned::Spanned,
5+
FnArg, ItemTrait, Pat, Receiver, TraitItem, TraitItemFn, parse_macro_input, parse_quote,
6+
spanned::Spanned,
67
};
78
use turbo_tasks_macros_shared::{
89
ValueTraitArguments, get_trait_default_impl_function_ident, get_trait_type_ident, is_self_used,
@@ -11,7 +12,7 @@ use turbo_tasks_macros_shared::{
1112
use crate::{
1213
func::{
1314
DefinitionContext, FunctionArguments, NativeFn, TurboFn, filter_inline_attributes,
14-
split_function_attributes,
15+
get_receiver_style, split_function_attributes,
1516
},
1617
global_name::global_name,
1718
};
@@ -94,15 +95,29 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
9495
let (func_args, attrs) = split_function_attributes(attrs);
9596
let func_args = match func_args {
9697
Ok(None) => {
97-
// There is no turbo_tasks::function annotation, preserve this item
98+
// There is no turbo_tasks::function annotation, preserve this item as is in the
99+
// trait
98100
items.push(item.clone());
99101
// But we still need to add a forwarding implementation to the
100102
// impl for `turbo_tasks::Dynamic<Box<dyn T>>`
101103
// This will have the same signature, but simply forward the call
102104
let mut args = Vec::new();
105+
let mut is_vc_receiver = false;
103106
for arg in &sig.inputs {
104107
let ident = match arg {
105-
FnArg::Receiver(_) => {
108+
FnArg::Receiver(Receiver { ty, .. }) => {
109+
match get_receiver_style(ty, &DefinitionContext::ValueTrait) {
110+
crate::func::ReceiverStyle::Reference => {
111+
is_vc_receiver = false;
112+
}
113+
crate::func::ReceiverStyle::Vc => {
114+
is_vc_receiver = true;
115+
}
116+
crate::func::ReceiverStyle::Error => {}
117+
}
118+
// We allow either `&self` or `self: Vc<Self>`
119+
// we cannot really validate Vc<Self> so instead we simply assume that
120+
// any type that isn't a reference is Vc<Self>
106121
continue;
107122
}
108123
FnArg::Typed(pat) => match &*pat.pat {
@@ -120,8 +135,17 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
120135
};
121136
args.push(ident);
122137
}
138+
if is_vc_receiver {
139+
item.span()
140+
.unwrap()
141+
.error(
142+
"`self: Vc<Self>` is only supported on trait items with a \
143+
`turbo-tasks::function` annotation",
144+
)
145+
.emit();
146+
}
123147
// Add a dummy implementation that derefences the box and delegates to the
124-
// actual implementation.
148+
// actual implementation. We need to conditionally add an await if it is async
125149
dynamic_trait_fns.push(if sig.asyncness.is_some() {
126150
quote! {
127151
#sig {

turbopack/crates/turbo-tasks/src/vc/resolved.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ where
243243
/// Returns `None` if the underlying value type does not implement `K`.
244244
///
245245
/// **Note:** if the trait `T` is required to implement `K`, use [`ResolvedVc::upcast`] instead.
246-
/// This provides stronger guarantees, removing the need for a [`Option`] return type.
246+
/// That method provides stronger guarantees, removing the need for a [`Option`] return type.
247247
///
248248
/// See also: [`Vc::try_resolve_sidecast`].
249249
pub fn try_sidecast<K>(this: Self) -> Option<ResolvedVc<K>>

turbopack/crates/turbopack-ecmascript/src/lib.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub use transform::{
8484
use turbo_rcstr::{RcStr, rcstr};
8585
use turbo_tasks::{
8686
FxDashMap, FxIndexMap, IntoTraitRef, NonLocalValue, ReadRef, ResolvedVc, TaskInput,
87-
TryFlatJoinIterExt, TryJoinIterExt, ValueToString, Vc, trace::TraceRawVcs,
87+
TryFlatJoinIterExt, TryJoinIterExt, Upcast, ValueToString, Vc, trace::TraceRawVcs,
8888
};
8989
use turbo_tasks_fs::{FileJsonContent, FileSystemPath, glob::Glob, rope::Rope};
9090
use turbopack_core::{
@@ -367,15 +367,28 @@ pub trait EcmascriptAnalyzable: Module + Asset {
367367
chunking_context: Vc<Box<dyn ChunkingContext>>,
368368
async_module_info: Option<Vc<AsyncModuleInfo>>,
369369
) -> Result<Vc<EcmascriptModuleContentOptions>>;
370+
}
370371

371-
#[turbo_tasks::function]
372+
pub trait EcmascriptAnalyzableExt {
372373
fn module_content(
373374
self: Vc<Self>,
374375
chunking_context: Vc<Box<dyn ChunkingContext>>,
375376
async_module_info: Option<Vc<AsyncModuleInfo>>,
376-
) -> Result<Vc<EcmascriptModuleContent>> {
377-
let own_options = self.module_content_options(chunking_context, async_module_info);
378-
Ok(EcmascriptModuleContent::new(own_options))
377+
) -> Vc<EcmascriptModuleContent>;
378+
}
379+
380+
impl<T> EcmascriptAnalyzableExt for T
381+
where
382+
T: EcmascriptAnalyzable + Upcast<Box<dyn EcmascriptAnalyzable>>,
383+
{
384+
fn module_content(
385+
self: Vc<Self>,
386+
chunking_context: Vc<Box<dyn ChunkingContext>>,
387+
async_module_info: Option<Vc<AsyncModuleInfo>>,
388+
) -> Vc<EcmascriptModuleContent> {
389+
let analyzable = Vc::upcast_non_strict::<Box<dyn EcmascriptAnalyzable>>(self);
390+
let own_options = analyzable.module_content_options(chunking_context, async_module_info);
391+
EcmascriptModuleContent::new(own_options)
379392
}
380393
}
381394

turbopack/crates/turbopack-ecmascript/src/side_effect_optimization/facade/chunk_item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use turbopack_core::{
88

99
use super::module::EcmascriptModuleFacadeModule;
1010
use crate::{
11-
EcmascriptAnalyzable,
11+
EcmascriptAnalyzableExt,
1212
chunk::{
1313
EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkPlaceable,
1414
EcmascriptChunkType,

turbopack/crates/turbopack-ecmascript/src/side_effect_optimization/locals/chunk_item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use turbopack_core::{
88

99
use super::module::EcmascriptModuleLocalsModule;
1010
use crate::{
11-
EcmascriptAnalyzable,
11+
EcmascriptAnalyzableExt,
1212
chunk::{EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkType},
1313
};
1414

turbopack/crates/turbopack-ecmascript/src/tree_shake/chunk_item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use turbopack_core::{
1010

1111
use super::asset::EcmascriptModulePartAsset;
1212
use crate::{
13-
EcmascriptAnalyzable,
13+
EcmascriptAnalyzableExt,
1414
chunk::{
1515
EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemOptions,
1616
EcmascriptChunkPlaceable, EcmascriptChunkType,

0 commit comments

Comments
 (0)