Repository: vercel/next.js
Pull request #78385: Update turbopack to syn2
Author: login: lukesandberg
Labels: name: examples
description: Issue was opened via the examples template.
name: type: next
name: create-next-app
description: Related to our CLI tool for quickly starting a new Next.js application.
name: Documentation
description: Related to Next.js' official documentation.
name: created-by: Turbopack team
description: PRs by the Turbopack team.
name: locked
name: tests
Created: 2025-04-21T18:19:46Z | Merged: 2025-04-23T21:31:22Z

Update turbopack to syn2

This delivers a number of basic API improvements and is required for us to adopt later rust editions.

I confirmed correctness by diffing `cargo expand` on the turbopack  crate across this change. 

Most of the changes are trivial updating to new names and ast structures, the more interesting ones were some changes to the `self` types, which improves consistency but broke a number of places were were working around the prior inconsistency (previously bare `self` or `&self` declarations were represented as `FnArg::Receiver` but a _typed_ receiver like `self: Vc<Self>` was a `FnArg::Typed`, now `self` declarations are always `FnArg::Receiver`)

Closes PACK-4383




Diff:
diff --git a/Cargo.lock b/Cargo.lock
index ae70994b432b..ec8517b74047 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8592,6 +8592,12 @@ version = "0.12.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
 
+[[package]]
+name = "target-triple"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790"
+
 [[package]]
 name = "tempfile"
 version = "3.14.0"
@@ -9166,14 +9172,15 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
 
 [[package]]
 name = "trybuild"
-version = "1.0.99"
+version = "1.0.104"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8"
+checksum = "6ae08be68c056db96f0e6c6dd820727cca756ced9e1f4cc7fdd20e2a55e23898"
 dependencies = [
  "glob",
  "serde",
  "serde_derive",
  "serde_json",
+ "target-triple",
  "termcolor",
  "toml 0.8.19",
 ]
@@ -9385,7 +9392,7 @@ dependencies = [
  "glob",
  "quote",
  "rustc-hash 2.1.0",
- "syn 1.0.109",
+ "syn 2.0.100",
  "turbo-tasks-macros-shared",
 ]
 
@@ -9512,7 +9519,7 @@ dependencies = [
  "quote",
  "regex",
  "rustc-hash 2.1.0",
- "syn 1.0.109",
+ "syn 2.0.100",
  "turbo-tasks-macros-shared",
 ]
 
@@ -9522,7 +9529,7 @@ version = "0.1.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.100",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index f61d9d3a7677..469116026d0d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -410,7 +410,7 @@ sourcemap = "9.0.0"
 strsim = "0.11.1"
 shrink-to-fit = "0.2.10"
 swc-rustc-hash = { package = "rustc-hash", version = "1.1.0" } # used with swc
-syn = "1.0.107"
+syn = "2.0.100"
 tempfile = "3.3.0"
 thread_local = "1.1.8"
 thiserror = "1.0.48"
diff --git a/turbopack/crates/turbo-tasks-build/src/lib.rs b/turbopack/crates/turbo-tasks-build/src/lib.rs
index 5065a025a1c8..9629ec4a4e42 100644
--- a/turbopack/crates/turbo-tasks-build/src/lib.rs
+++ b/turbopack/crates/turbo-tasks-build/src/lib.rs
@@ -12,7 +12,7 @@ use quote::ToTokens;
 use rustc_hash::{FxHashMap, FxHashSet};
 use syn::{
     parse_quote, Attribute, Ident, Item, ItemEnum, ItemFn, ItemImpl, ItemMacro, ItemMod,
-    ItemStruct, ItemTrait, TraitItem, TraitItemMethod,
+    ItemStruct, ItemTrait, TraitItem, TraitItemFn,
 };
 use turbo_tasks_macros_shared::{
     get_impl_function_ident, get_native_function_ident, get_path_ident,
@@ -286,7 +286,7 @@ impl RegisterContext<'_> {
             }
 
             for item in &impl_item.items {
-                if let syn::ImplItem::Method(method_item) = item {
+                if let syn::ImplItem::Fn(method_item) = item {
                     // TODO: if method_item.attrs.iter().any(|a|
                     // is_attribute(a,
                     // "function")) {
@@ -371,7 +371,7 @@ impl RegisterContext<'_> {
             let trait_ident = &trait_item.ident;
 
             for item in &trait_item.items {
-                if let TraitItem::Method(TraitItemMethod {
+                if let TraitItem::Fn(TraitItemFn {
                     default: Some(_),
                     sig,
                     ..
@@ -583,7 +583,7 @@ fn has_turbo_attribute(attrs: &[Attribute], name: &str) -> bool {
 }
 
 fn is_turbo_attribute(attr: &Attribute, name: &str) -> bool {
-    let path = &attr.path;
+    let path = attr.path();
     if path.leading_colon.is_some() {
         return false;
     }
@@ -598,7 +598,7 @@ fn is_turbo_attribute(attr: &Attribute, name: &str) -> bool {
 }
 
 fn is_cfg_attribute(attr: &Attribute) -> bool {
-    attr.path
+    attr.path()
         .get_ident()
         .is_some_and(|ident| ident == "cfg" || ident == "cfg_attr")
 }
diff --git a/turbopack/crates/turbo-tasks-macros-shared/src/primitive_input.rs b/turbopack/crates/turbo-tasks-macros-shared/src/primitive_input.rs
index ee17010baeac..688fe1cdbd8e 100644
--- a/turbopack/crates/turbo-tasks-macros-shared/src/primitive_input.rs
+++ b/turbopack/crates/turbo-tasks-macros-shared/src/primitive_input.rs
@@ -1,7 +1,6 @@
 use proc_macro2::Span;
 use syn::{
     parse::{Parse, ParseStream},
-    punctuated::Punctuated,
     spanned::Spanned,
     Meta, Result, Token, Type,
 };
@@ -20,7 +19,7 @@ impl Parse for PrimitiveInput {
             manual_shrink_to_fit: None,
         };
         if input.parse::<Option<Token![,]>>()?.is_some() {
-            let punctuated: Punctuated<Meta, Token![,]> = input.parse_terminated(Meta::parse)?;
+            let punctuated = input.parse_terminated(Meta::parse, Token![,])?;
             for meta in punctuated {
                 match (
                     meta.path()
diff --git a/turbopack/crates/turbo-tasks-macros-shared/src/value_trait_arguments.rs b/turbopack/crates/turbo-tasks-macros-shared/src/value_trait_arguments.rs
index f43e8e21e5a3..323b8a9f00b8 100644
--- a/turbopack/crates/turbo-tasks-macros-shared/src/value_trait_arguments.rs
+++ b/turbopack/crates/turbo-tasks-macros-shared/src/value_trait_arguments.rs
@@ -1,7 +1,6 @@
 use proc_macro2::Span;
 use syn::{
     parse::{Parse, ParseStream},
-    punctuated::Punctuated,
     spanned::Spanned,
     Meta, Token,
 };
@@ -32,7 +31,7 @@ impl Parse for ValueTraitArguments {
             return Ok(result);
         }
 
-        let punctuated: Punctuated<Meta, Token![,]> = input.parse_terminated(Meta::parse)?;
+        let punctuated = input.parse_terminated(Meta::parse, Token![,])?;
         for meta in punctuated {
             match meta.path().get_ident().map(ToString::to_string).as_deref() {
                 Some("no_debug") => {
diff --git a/turbopack/crates/turbo-tasks-macros-tests/Cargo.toml b/turbopack/crates/turbo-tasks-macros-tests/Cargo.toml
index 0a4594fc2aa3..4972d8970d9e 100644
--- a/turbopack/crates/turbo-tasks-macros-tests/Cargo.toml
+++ b/turbopack/crates/turbo-tasks-macros-tests/Cargo.toml
@@ -9,7 +9,7 @@ edition = "2021"
 anyhow = { workspace = true }
 serde = { workspace = true }
 tokio = { workspace = true }
-trybuild = { version = "1.0.97" }
+trybuild = { version = "1.0.104" }
 turbo-tasks = { workspace = true }
 turbo-tasks-testing = { workspace = true }
 turbo-tasks-memory = { workspace = true }
diff --git a/turbopack/crates/turbo-tasks-macros-tests/tests/function/fail_operation_method_self_type.stderr b/turbopack/crates/turbo-tasks-macros-tests/tests/function/fail_operation_method_self_type.stderr
index 0a167e2e1632..7abfa9badd4f 100644
--- a/turbopack/crates/turbo-tasks-macros-tests/tests/function/fail_operation_method_self_type.stderr
+++ b/turbopack/crates/turbo-tasks-macros-tests/tests/function/fail_operation_method_self_type.stderr
@@ -13,7 +13,7 @@ error[E0307]: invalid `self` parameter type: `OperationVc<Foobar>`
    = note: type of `self` must be `Self` or some type implementing `Receiver`
    = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
-error[E0277]: the trait bound `fn(...) -> ... {...::arbitrary_self_type_turbo_tasks_function_inline}: IntoTaskFnWithThis<_, _, _>` is not satisfied
+error[E0277]: the trait bound `fn(OperationVc<Foobar>) -> Vc<()> {Foobar::arbitrary_self_type_turbo_tasks_function_inline}: turbo_tasks::task::function::IntoTaskFnWithThis<_, _, _>` is not satisfied
   --> tests/function/fail_operation_method_self_type.rs:10:1
    |
 10 | #[turbo_tasks::value_impl]
@@ -29,5 +29,4 @@ note: required by a bound in `NativeFunction::new_method`
 ...
    |         I: IntoTaskFnWithThis<Mode, This, Inputs>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `NativeFunction::new_method`
-   = note: consider using `--verbose` to print the full type name to the console
    = note: this error originates in the attribute macro `turbo_tasks::value_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/turbopack/crates/turbo-tasks-macros-tests/tests/function/fail_operation_method_self_type_base_vc.stderr b/turbopack/crates/turbo-tasks-macros-tests/tests/function/fail_operation_method_self_type_base_vc.stderr
index ff17cba4aaca..09588ee77e2d 100644
--- a/turbopack/crates/turbo-tasks-macros-tests/tests/function/fail_operation_method_self_type_base_vc.stderr
+++ b/turbopack/crates/turbo-tasks-macros-tests/tests/function/fail_operation_method_self_type_base_vc.stderr
@@ -3,25 +3,3 @@ error: methods taking `self` are not supported with `operation`
    |
 13 |     fn arbitrary_self_type_base_vc(self: Vc<Self>) -> Vc<()> {
    |                                    ^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `Vc<Foobar>: NonLocalValue` is not satisfied
-  --> tests/function/fail_operation_method_self_type_base_vc.rs:13:42
-   |
-13 |     fn arbitrary_self_type_base_vc(self: Vc<Self>) -> Vc<()> {
-   |                                          ^^^^^^^^ the trait `NonLocalValue` is not implemented for `Vc<Foobar>`
-   |
-   = help: the following other types implement trait `NonLocalValue`:
-             &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 `assert_argument_is_non_local_value`
-  --> $WORKSPACE/turbopack/crates/turbo-tasks/src/macro_helpers.rs
-   |
-   | pub fn assert_argument_is_non_local_value<Argument: NonLocalValue>() {}
-   |                                                     ^^^^^^^^^^^^^ required by this bound in `assert_argument_is_non_local_value`
diff --git a/turbopack/crates/turbo-tasks-macros/src/derive/mod.rs b/turbopack/crates/turbo-tasks-macros/src/derive/mod.rs
index b812fd09bf04..12865ce9942b 100644
--- a/turbopack/crates/turbo-tasks-macros/src/derive/mod.rs
+++ b/turbopack/crates/turbo-tasks-macros/src/derive/mod.rs
@@ -11,7 +11,7 @@ pub use deterministic_hash_macro::derive_deterministic_hash;
 pub use key_value_pair_macro::derive_key_value_pair;
 pub use non_local_value_macro::derive_non_local_value;
 pub use operation_value_macro::derive_operation_value;
-use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta};
+use syn::{punctuated::Punctuated, spanned::Spanned, Attribute, Meta, Token};
 pub use task_input_macro::derive_task_input;
 pub use trace_raw_vcs_macro::derive_trace_raw_vcs;
 pub use value_debug_format_macro::derive_value_debug_format;
@@ -31,34 +31,48 @@ impl From<&[Attribute]> for FieldAttributes {
 
         for attr in attrs {
             if !attr
-                .path
+                .path()
                 .get_ident()
                 .map(|ident| *ident == "turbo_tasks")
                 .unwrap_or_default()
             {
                 continue;
             }
-            if let Ok(Meta::List(MetaList { nested, .. })) = attr
-                .parse_meta()
-                .map_err(|err| err.span().unwrap().error(err.to_string()).emit())
+            let nested = match attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
             {
-                for meta in nested {
-                    if let NestedMeta::Meta(Meta::Path(path)) = &meta {
-                        match path.get_ident().map(|ident| ident.to_string()).as_deref() {
-                            Some("trace_ignore") => result.trace_ignore = true,
-                            Some("debug_ignore") => result.debug_ignore = true,
-                            _ => path
+                Ok(punctuated) => punctuated,
+                Err(e) => {
+                    attr.meta
+                        .span()
+                        .unwrap()
+                        .error(format!(
+                            "expected `trace_ignore` or `debug_ignore`, got: {e}"
+                        ))
+                        .emit();
+                    Punctuated::default()
+                }
+            };
+            for meta in nested {
+                match meta {
+                    Meta::Path(path) => {
+                        if path.is_ident("trace_ignore") {
+                            result.trace_ignore = true;
+                        } else if path.is_ident("debug_ignore") {
+                            result.debug_ignore = true;
+                        } else {
+                            path.span()
                                 .span()
                                 .unwrap()
                                 .error("expected `trace_ignore` or `debug_ignore`")
-                                .emit(),
+                                .emit()
                         }
-                    } else {
-                        meta.span()
-                            .unwrap()
-                            .error("expected `trace_ignore` or `debug_ignore`")
-                            .emit();
                     }
+                    _ => meta
+                        .path()
+                        .span()
+                        .unwrap()
+                        .error("expected `trace_ignore` or `debug_ignore`")
+                        .emit(),
                 }
             }
         }
diff --git a/turbopack/crates/turbo-tasks-macros/src/func.rs b/turbopack/crates/turbo-tasks-macros/src/func.rs
index e27682998cb1..7795106626c4 100644
--- a/turbopack/crates/turbo-tasks-macros/src/func.rs
+++ b/turbopack/crates/turbo-tasks-macros/src/func.rs
@@ -4,16 +4,15 @@ use proc_macro2::{Ident, Span, TokenStream};
 use quote::{quote, quote_spanned, ToTokens};
 use rustc_hash::FxHashSet;
 use syn::{
-    parenthesized,
     parse::{Parse, ParseStream},
     parse_quote, parse_quote_spanned,
     punctuated::{Pair, Punctuated},
     spanned::Spanned,
-    token::Paren,
     visit_mut::VisitMut,
     AngleBracketedGenericArguments, Attribute, Block, Expr, ExprBlock, ExprPath, FnArg,
-    GenericArgument, Local, Meta, Pat, PatIdent, PatType, Path, PathArguments, PathSegment,
-    Receiver, ReturnType, Signature, Stmt, Token, Type, TypeGroup, TypePath, TypeTuple,
+    GenericArgument, Local, LocalInit, Meta, Pat, PatIdent, PatType, Path, PathArguments,
+    PathSegment, Receiver, ReturnType, Signature, Stmt, Token, Type, TypeGroup, TypePath,
+    TypeTuple,
 };
 
 #[derive(Debug)]
@@ -84,8 +83,8 @@ impl TurboFn<'_> {
                     receiver @ Receiver {
                         attrs,
                         self_token,
-                        reference,
-                        mutability,
+                        ty: self_type,
+                        ..
                     },
                 ) => {
                     if !attrs.is_empty() {
@@ -93,7 +92,7 @@ impl TurboFn<'_> {
                             .span()
                             .unwrap()
                             .error(format!(
-                                "{} do not support attributes on arguments",
+                                "{} do not support attributes on self",
                                 definition_context.function_type(),
                             ))
                             .emit();
@@ -109,61 +108,53 @@ impl TurboFn<'_> {
                         _ => &definition_context,
                     };
 
-                    if !attrs.is_empty() {
-                        receiver
-                            .span()
-                            .unwrap()
-                            .error(format!(
-                                "{} do not support attributes on self",
-                                definition_context.function_type(),
-                            ))
-                            .emit();
-                        return None;
-                    }
-
-                    if mutability.is_some() {
-                        receiver
-                            .span()
-                            .unwrap()
-                            .error(format!(
-                                "{} cannot take self by mutable reference, use &self or self: \
-                                 Vc<Self> instead",
-                                definition_context.function_type(),
-                            ))
-                            .emit();
-                        return None;
-                    }
+                    match self_type.as_ref() {
+                        // we allow `&Self` but not `&mut Self`
+                        syn::Type::Reference(type_reference) => {
+                            if let Some(m) = type_reference.mutability {
+                                m.span()
+                                    .unwrap()
+                                    .error(format!(
+                                        "{} cannot take self by mutable reference, use &self or \
+                                         self: Vc<Self> instead",
+                                        definition_context.function_type(),
+                                    ))
+                                    .emit();
+                                return None;
+                            }
 
-                    match &reference {
-                        None => {
-                            receiver
-                                .span()
-                                .unwrap()
-                                .error(format!(
-                                    "{} cannot take self by value, use &self or self: Vc<Self> \
-                                     instead",
-                                    definition_context.function_type(),
-                                ))
-                                .emit();
-                            return None;
+                            match type_reference.elem.as_ref() {
+                                syn::Type::Path(TypePath { qself: None, path })
+                                    if path.is_ident("Self") => {}
+                                _ => {
+                                    self_type
+                                        .span()
+                                        .unwrap()
+                                        .error(
+                                            "Unexpected `self` type, use `&self` or `self: \
+                                             Vc<Self>",
+                                        )
+                                        .emit();
+                                    return None;
+                                }
+                            }
                         }
-                        Some((_, Some(lifetime))) => {
-                            lifetime
+                        syn::Type::Path(_) => {}
+                        _ => {
+                            self_type
                                 .span()
                                 .unwrap()
-                                .error(format!(
-                                    "{} cannot take self by reference with a custom lifetime, use \
-                                     &self or self: Vc<Self> instead",
-                                    definition_context.function_type(),
-                                ))
+                                .error("Unexpected `self` type, use `&self` or `self: Vc<Self>")
                                 .emit();
                             return None;
                         }
-                        _ => {}
                     }
+                    // We don't validate that the user provided a valid `turbo_tasks::Vc<Self>`
+                    // here. We'll rely on the compiler to emit an error if the user provided an
+                    // invalid receiver type
 
                     this = Some(Input {
-                        ident: Ident::new("self", self_token.span()),
+                        ident: Ident::from(*self_token),
                         ty: parse_quote! { turbo_tasks::Vc<Self> },
                     });
                 }
@@ -181,49 +172,27 @@ impl TurboFn<'_> {
                     }
 
                     if let Pat::Ident(ident) = &*typed.pat {
-                        if ident.ident == "self" {
-                            if let DefinitionContext::NakedFn = definition_context {
-                                // The function is not associated. The compiler will emit an error
-                                // on its own.
+                        match definition_context {
+                            DefinitionContext::NakedFn | DefinitionContext::ValueInherentImpl => {}
+                            DefinitionContext::ValueTraitImpl | DefinitionContext::ValueTrait => {
+                                typed
+                                    .span()
+                                    .unwrap()
+                                    .error(format!(
+                                        "{} must accept &self or self: Vc<Self> as the first \
+                                         argument",
+                                        definition_context.function_type(),
+                                    ))
+                                    .emit();
                                 return None;
-                            };
-
-                            // We don't validate that the user provided a valid
-                            // `turbo_tasks::Vc<Self>` here.
-                            // We'll rely on the compiler to emit an error
-                            // if the user provided an invalid receiver type
-
-                            let ident = ident.ident.clone();
-
-                            this = Some(Input {
-                                ident,
-                                ty: parse_quote! { turbo_tasks::Vc<Self> },
-                            });
-                        } else {
-                            match definition_context {
-                                DefinitionContext::NakedFn
-                                | DefinitionContext::ValueInherentImpl => {}
-                                DefinitionContext::ValueTraitImpl
-                                | DefinitionContext::ValueTrait => {
-                                    typed
-                                        .span()
-                                        .unwrap()
-                                        .error(format!(
-                                            "{} must accept &self or self: Vc<Self> as the first \
-                                             argument",
-                                            definition_context.function_type(),
-                                        ))
-                                        .emit();
-                                    return None;
-                                }
                             }
-                            let ident = ident.ident.clone();
-
-                            exposed_inputs.push(Input {
-                                ident,
-                                ty: (*typed.ty).clone(),
-                            });
                         }
+                        let ident = ident.ident.clone();
+
+                        exposed_inputs.push(Input {
+                            ident,
+                            ty: (*typed.ty).clone(),
+                        });
                     } else {
                         // We can't support destructuring patterns (or other kinds of patterns).
                         let ident = Ident::new("arg1", typed.pat.span());
@@ -359,83 +328,104 @@ impl TurboFn<'_> {
                 inline_inputs_identifier_filter(&pat_id.ident)
             })
             .enumerate()
-            .map(|(idx, arg)| match arg {
-                FnArg::Receiver(_) => (arg.clone(), None),
-                FnArg::Typed(pat_type) => {
-                    if self.operation {
-                        // operations shouldn't have their arguments rewritten, they require all
-                        // arguments are explicitly `NonLocalValue`s
-                        return (arg.clone(), None);
-                    }
-                    let Cow::Owned(expanded_ty) = expand_task_input_type(&pat_type.ty) else {
-                        // common-case: skip if no type conversion is needed
-                        return (arg.clone(), None);
-                    };
-
-                    let arg_id = if let Pat::Ident(pat_id) = &*pat_type.pat {
-                        // common case: argument is just an identifier
-                        Cow::Borrowed(&pat_id.ident)
-                    } else {
-                        // argument is a pattern, we need to rewrite it to a unique identifier
-                        Cow::Owned(Ident::new(
-                            &format!("arg{idx}"),
-                            pat_type.span().resolved_at(Span::mixed_site()),
-                        ))
-                    };
-
-                    let arg = FnArg::Typed(PatType {
-                        pat: Box::new(Pat::Ident(PatIdent {
-                            attrs: Vec::new(),
-                            by_ref: None,
-                            mutability: None,
-                            ident: arg_id.clone().into_owned(),
-                            subpat: None,
-                        })),
-                        ty: Box::new(expanded_ty),
-                        ..pat_type.clone()
-                    });
-
-                    // We can't shadow `self` variables, so it this argument is a `self` argument,
-                    // generate a new identifier, and rewrite the body of the function later to use
-                    // that new identifier.
-                    // NOTE: arbitrary self types aren't `FnArg::Receiver` on syn 1.x (fixed in 2.x)
-                    let transform_pat = match &*pat_type.pat {
-                        Pat::Ident(pat_id) if pat_id.ident == "self" => {
-                            let shadow_self_id = Ident::new(
-                                "turbo_tasks_self",
-                                Span::mixed_site().located_at(pat_id.ident.span()),
-                            );
-                            shadow_self = Some(shadow_self_id.clone());
-                            Pat::Ident(PatIdent {
-                                ident: shadow_self_id,
-                                ..pat_id.clone()
-                            })
-                        }
-                        pat => pat.clone(),
-                    };
-
-                    // convert an argument of type `FromTaskInput<T>::TaskInput` into `T`.
-                    // essentially, replace any instances of `Vc` with `ResolvedVc`.
-                    let orig_ty = &*pat_type.ty;
-                    let transform_stmt = Some(Stmt::Local(Local {
+            .map(|(idx, arg)| {
+                if self.operation {
+                    // operations shouldn't have their arguments rewritten, they require all
+                    // arguments are explicitly `NonLocalValue`s
+                    return (arg.clone(), None);
+                }
+                let (FnArg::Receiver(Receiver { ty, .. }) | FnArg::Typed(PatType { ty, .. })) = arg;
+                let Cow::Owned(expanded_ty) = expand_task_input_type(ty) else {
+                    // common-case: skip if no type conversion is needed
+                    return (arg.clone(), None);
+                };
+                // Helper to produce the transform statement
+                let transform_from_task_input = |arg_id: Cow<'_, Ident>, pat: Pat| {
+                    Stmt::Local(Local {
                         attrs: Vec::new(),
                         let_token: Default::default(),
-                        pat: transform_pat,
-                        init: Some((
-                            Default::default(),
+                        pat,
+                        init: Some(LocalInit {
+                            eq_token: Default::default(),
                             // we know the argument implements `FromTaskInput` because
                             // `expand_task_input_type` returned `Cow::Owned`
-                            parse_quote_spanned! {
-                                pat_type.span() =>
-                                <#orig_ty as turbo_tasks::task::FromTaskInput>::from_task_input(
+                            expr: parse_quote_spanned! {
+                                arg.span() =>
+                                <#ty as turbo_tasks::task::FromTaskInput>::from_task_input(
                                     #arg_id
                                 )
                             },
-                        )),
+                            diverge: None,
+                        }),
                         semi_token: Default::default(),
-                    }));
+                    })
+                };
+                match arg {
+                    FnArg::Receiver(
+                        receiver @ Receiver {
+                            attrs, self_token, ..
+                        },
+                    ) => {
+                        let arg = FnArg::Receiver(Receiver {
+                            attrs: Vec::new(),
+                            mutability: None,
+                            ty: Box::new(expanded_ty),
+                            ..receiver.clone()
+                        });
+
+                        // We can't shadow `self` variables, so it this argument is a `self`
+                        // argument, generate a new identifier, and rewrite
+                        // the body of the function later to use
+                        // that new identifier.
+                        let shadow_self_id = Ident::new(
+                            "turbo_tasks_self",
+                            Span::mixed_site().located_at(self_token.span()),
+                        );
+                        shadow_self = Some(shadow_self_id.clone());
+                        let shadow_self_pattern = Pat::Ident(PatIdent {
+                            ident: shadow_self_id,
+                            attrs: attrs.clone(),
+                            mutability: None,
+                            by_ref: None,
+                            subpat: None,
+                        });
+                        let self_ident = Cow::Owned(Ident::new("self", self_token.span()));
+                        let transform_stmt =
+                            transform_from_task_input(self_ident, shadow_self_pattern);
+
+                        (arg, Some(transform_stmt))
+                    }
+                    FnArg::Typed(pat_type) => {
+                        let arg_id = if let Pat::Ident(pat_id) = &*pat_type.pat {
+                            // common case: argument is just an identifier
+                            Cow::Borrowed(&pat_id.ident)
+                        } else {
+                            // argument is a pattern, we need to rewrite it to a unique identifier
+                            Cow::Owned(Ident::new(
+                                &format!("arg{idx}"),
+                                pat_type.span().resolved_at(Span::mixed_site()),
+                            ))
+                        };
+
+                        let arg = FnArg::Typed(PatType {
+                            pat: Box::new(Pat::Ident(PatIdent {
+                                attrs: Vec::new(),
+                                by_ref: None,
+                                mutability: None,
+                                ident: arg_id.clone().into_owned(),
+                                subpat: None,
+                            })),
+                            ty: Box::new(expanded_ty),
+                            ..pat_type.clone()
+                        });
 
-                    (arg, transform_stmt)
+                        // convert an argument of type `FromTaskInput<T>::TaskInput` into `T`.
+                        // essentially, replace any instances of `Vc` with `ResolvedVc`.
+                        let pat = (*pat_type.pat).clone();
+                        let transform_stmt = transform_from_task_input(arg_id, pat);
+
+                        (arg, Some(transform_stmt))
+                    }
                 }
             })
             .unzip();
@@ -452,21 +442,25 @@ impl TurboFn<'_> {
             Cow::Borrowed(orig_block)
         } else {
             let mut stmts = transform_stmts;
-            stmts.push(Stmt::Expr(Expr::Block(ExprBlock {
-                attrs: Vec::new(),
-                label: None,
-                block: if let Some(shadow_self) = shadow_self {
-                    // if `self` is a `ResolvedVc<Self>`, we need to rewrite references to `self`
-                    let mut block = orig_block.clone();
-                    RewriteSelfVisitMut {
-                        self_ident: shadow_self,
-                    }
-                    .visit_block_mut(&mut block);
-                    block
-                } else {
-                    orig_block.clone()
-                },
-            })));
+            stmts.push(Stmt::Expr(
+                Expr::Block(ExprBlock {
+                    attrs: Vec::new(),
+                    label: None,
+                    block: if let Some(shadow_self) = shadow_self {
+                        // if `self` is a `ResolvedVc<Self>`, we need to rewrite references to
+                        // `self`
+                        let mut block = orig_block.clone();
+                        RewriteSelfVisitMut {
+                            self_ident: shadow_self,
+                        }
+                        .visit_block_mut(&mut block);
+                        block
+                    } else {
+                        orig_block.clone()
+                    },
+                }),
+                None,
+            ));
             Cow::Owned(Block {
                 brace_token: Default::default(),
                 stmts,
@@ -706,42 +700,15 @@ enum IoMarker {
     Network,
 }
 
-/// Unwraps a parenthesized set of tokens.
-///
-/// Syn's lower-level [`parenthesized`] macro which this uses requires a
-/// [`ParseStream`] and cannot be used with [`parse_macro_input`],
-/// [`syn::parse2`] or anything else accepting a [`TokenStream`]. This can be
-/// used with those [`TokenStream`]-based parsing APIs.
-pub struct Parenthesized<T: Parse> {
-    pub _paren_token: Paren,
-    pub inner: T,
-}
-
-impl<T: Parse> Parse for Parenthesized<T> {
-    fn parse(input: ParseStream) -> syn::Result<Self> {
-        let inner;
-        Ok(Self {
-            _paren_token: parenthesized!(inner in input),
-            inner: <T>::parse(&inner)?,
-        })
-    }
-}
-
-/// A newtype wrapper for [`Option<Parenthesized>`][Parenthesized] that
-/// implements [`Parse`].
-pub struct MaybeParenthesized<T: Parse> {
-    pub parenthesized: Option<Parenthesized<T>>,
-}
-
-impl<T: Parse> Parse for MaybeParenthesized<T> {
-    fn parse(input: ParseStream) -> syn::Result<Self> {
-        Ok(Self {
-            parenthesized: if input.peek(Paren) {
-                Some(Parenthesized::<T>::parse(input)?)
-            } else {
-                None
-            },
-        })
+// Optionally parses `T` from a parethensized attributes, returns `T::default` otherwise.
+pub fn parse_with_optional_parens<T: Parse + Default>(attr: &Attribute) -> syn::Result<T> {
+    match &attr.meta {
+        Meta::Path(_) => Ok(T::default()),
+        Meta::List(meta) => meta.parse_args_with(T::parse),
+        Meta::NameValue(meta) => Err(syn::Error::new(
+            meta.eq_token.span,
+            "Expected parenthized parameters",
+        )),
     }
 }
 
@@ -769,7 +736,7 @@ pub struct FunctionArguments {
 impl Parse for FunctionArguments {
     fn parse(input: ParseStream) -> syn::Result<Self> {
         let mut parsed_args = FunctionArguments::default();
-        let punctuated: Punctuated<Meta, Token![,]> = input.parse_terminated(Meta::parse)?;
+        let punctuated = input.parse_terminated(Meta::parse, Token![,])?;
         for meta in punctuated {
             match (
                 meta.path()
@@ -1166,7 +1133,7 @@ pub fn filter_inline_attributes<'a>(
     // inline functions use #[doc(hidden)], so it's not useful to preserve/duplicate docs
     attrs
         .into_iter()
-        .filter(|attr| attr.path.get_ident().is_none_or(|id| id != "doc"))
+        .filter(|attr| attr.path().get_ident().is_none_or(|id| id != "doc"))
         .collect()
 }
 
diff --git a/turbopack/crates/turbo-tasks-macros/src/value_impl_macro.rs b/turbopack/crates/turbo-tasks-macros/src/value_impl_macro.rs
index bf326b3986e8..4444f5a05827 100644
--- a/turbopack/crates/turbo-tasks-macros/src/value_impl_macro.rs
+++ b/turbopack/crates/turbo-tasks-macros/src/value_impl_macro.rs
@@ -4,10 +4,9 @@ use quote::{quote, ToTokens};
 use syn::{
     parse::{Parse, ParseStream},
     parse_macro_input, parse_quote,
-    punctuated::Punctuated,
     spanned::Spanned,
-    Attribute, Error, Generics, ImplItem, ImplItemMethod, ItemImpl, Lit, LitStr, Meta,
-    MetaNameValue, Path, Result, Token, Type,
+    Attribute, Error, Expr, ExprLit, Generics, ImplItem, ImplItemFn, ItemImpl, Lit, LitStr, Meta,
+    MetaNameValue, Path, Token, Type,
 };
 use turbo_tasks_macros_shared::{
     get_inherent_impl_function_id_ident, get_inherent_impl_function_ident, get_path_ident,
@@ -16,12 +15,12 @@ use turbo_tasks_macros_shared::{
 };
 
 use crate::func::{
-    filter_inline_attributes, DefinitionContext, FunctionArguments, MaybeParenthesized, NativeFn,
-    TurboFn,
+    filter_inline_attributes, parse_with_optional_parens, DefinitionContext, FunctionArguments,
+    NativeFn, TurboFn,
 };
 
 fn is_attribute(attr: &Attribute, name: &str) -> bool {
-    let path = &attr.path;
+    let path = &attr.path();
     if path.leading_colon.is_some() {
         return false;
     }
@@ -45,8 +44,7 @@ fn split_function_attributes<'a>(
         .partition(|attr| is_attribute(attr, "function"));
     let func_args = if let Some(func_attr) = func_attrs_vec.first() {
         if func_attrs_vec.len() == 1 {
-            syn::parse2::<MaybeParenthesized<FunctionArguments>>(func_attr.tokens.clone())
-                .map(|a| a.parenthesized.map(|a| a.inner).unwrap_or_default())
+            parse_with_optional_parens::<FunctionArguments>(func_attr)
         } else {
             Err(syn::Error::new(
                 func_attr.span(),
@@ -67,9 +65,9 @@ struct ValueImplArguments {
 }
 
 impl Parse for ValueImplArguments {
-    fn parse(input: ParseStream) -> Result<Self> {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
         let mut result = ValueImplArguments { ident: None };
-        let punctuated: Punctuated<Meta, Token![,]> = input.parse_terminated(Meta::parse)?;
+        let punctuated = input.parse_terminated(Meta::parse, Token![,])?;
         for meta in punctuated {
             match (
                 meta.path()
@@ -82,7 +80,11 @@ impl Parse for ValueImplArguments {
                 (
                     "ident",
                     Meta::NameValue(MetaNameValue {
-                        lit: Lit::Str(lit), ..
+                        value:
+                            Expr::Lit(ExprLit {
+                                lit: Lit::Str(lit), ..
+                            }),
+                        ..
                     }),
                 ) => {
                     result.ident = Some(lit);
@@ -109,7 +111,7 @@ pub fn value_impl(args: TokenStream, input: TokenStream) -> TokenStream {
         let mut errors = Vec::new();
 
         for item in items.iter() {
-            if let ImplItem::Method(ImplItemMethod {
+            if let ImplItem::Fn(ImplItemFn {
                 attrs,
                 vis,
                 defaultness: _,
@@ -212,7 +214,7 @@ pub fn value_impl(args: TokenStream, input: TokenStream) -> TokenStream {
         let mut errors = Vec::new();
 
         for item in items.iter() {
-            if let ImplItem::Method(ImplItemMethod {
+            if let ImplItem::Fn(ImplItemFn {
                 sig, attrs, block, ..
             }) = item
             {
diff --git a/turbopack/crates/turbo-tasks-macros/src/value_macro.rs b/turbopack/crates/turbo-tasks-macros/src/value_macro.rs
index aa8d84f28a2e..f55d8f48412e 100644
--- a/turbopack/crates/turbo-tasks-macros/src/value_macro.rs
+++ b/turbopack/crates/turbo-tasks-macros/src/value_macro.rs
@@ -7,10 +7,9 @@ use regex::Regex;
 use syn::{
     parse::{Parse, ParseStream},
     parse_macro_input, parse_quote,
-    punctuated::Punctuated,
     spanned::Spanned,
-    Error, Fields, FieldsUnnamed, Generics, Item, ItemEnum, ItemStruct, Lit, LitStr, Meta,
-    MetaNameValue, Result, Token,
+    Error, Expr, ExprLit, Fields, FieldsUnnamed, Generics, Item, ItemEnum, ItemStruct, Lit, LitStr,
+    Meta, MetaNameValue, Result, Token,
 };
 use turbo_tasks_macros_shared::{
     get_register_value_type_ident, get_value_type_id_ident, get_value_type_ident,
@@ -124,7 +123,7 @@ impl Parse for ValueArguments {
             transparent: false,
             operation: None,
         };
-        let punctuated: Punctuated<Meta, Token![,]> = input.parse_terminated(Meta::parse)?;
+        let punctuated = input.parse_terminated(Meta::parse, Token![,])?;
         for meta in punctuated {
             match (
                 meta.path()
@@ -141,7 +140,11 @@ impl Parse for ValueArguments {
                 (
                     "into",
                     Meta::NameValue(MetaNameValue {
-                        lit: Lit::Str(str), ..
+                        value:
+                            Expr::Lit(ExprLit {
+                                lit: Lit::Str(str), ..
+                            }),
+                        ..
                     }),
                 ) => {
                     result.into_mode = IntoMode::try_from(str)?;
@@ -149,7 +152,11 @@ impl Parse for ValueArguments {
                 (
                     "serialization",
                     Meta::NameValue(MetaNameValue {
-                        lit: Lit::Str(str), ..
+                        value:
+                            Expr::Lit(ExprLit {
+                                lit: Lit::Str(str), ..
+                            }),
+                        ..
                     }),
                 ) => {
                     result.serialization_mode = SerializationMode::try_from(str)?;
@@ -157,7 +164,11 @@ impl Parse for ValueArguments {
                 (
                     "cell",
                     Meta::NameValue(MetaNameValue {
-                        lit: Lit::Str(str), ..
+                        value:
+                            Expr::Lit(ExprLit {
+                                lit: Lit::Str(str), ..
+                            }),
+                        ..
                     }),
                 ) => {
                     result.cell_mode = CellMode::try_from(str)?;
@@ -165,7 +176,11 @@ impl Parse for ValueArguments {
                 (
                     "eq",
                     Meta::NameValue(MetaNameValue {
-                        lit: Lit::Str(str), ..
+                        value:
+                            Expr::Lit(ExprLit {
+                                lit: Lit::Str(str), ..
+                            }),
+                        ..
                     }),
                 ) => {
                     result.manual_eq = if str.value() == "manual" {
diff --git a/turbopack/crates/turbo-tasks-macros/src/value_trait_macro.rs b/turbopack/crates/turbo-tasks-macros/src/value_trait_macro.rs
index d3a5510734b1..395348e5d15a 100644
--- a/turbopack/crates/turbo-tasks-macros/src/value_trait_macro.rs
+++ b/turbopack/crates/turbo-tasks-macros/src/value_trait_macro.rs
@@ -1,9 +1,7 @@
 use proc_macro::TokenStream;
 use proc_macro2::{Ident, TokenStream as TokenStream2};
 use quote::{quote, quote_spanned};
-use syn::{
-    parse_macro_input, parse_quote, spanned::Spanned, ItemTrait, TraitItem, TraitItemMethod,
-};
+use syn::{parse_macro_input, parse_quote, spanned::Spanned, ItemTrait, TraitItem, TraitItemFn};
 use turbo_tasks_macros_shared::{
     get_trait_default_impl_function_id_ident, get_trait_default_impl_function_ident,
     get_trait_type_id_ident, get_trait_type_ident, ValueTraitArguments,
@@ -30,6 +28,7 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
         auto_token,
         generics,
         brace_token: _,
+        restriction: _,
     } = &item;
 
     if unsafety.is_some() {
@@ -70,7 +69,7 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
     let mut items = Vec::with_capacity(raw_items.len());
 
     for item in raw_items.iter() {
-        let TraitItem::Method(TraitItemMethod {
+        let TraitItem::Fn(TraitItemFn {
             sig,
             default,
             attrs,
@@ -177,7 +176,7 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
             None
         };
 
-        items.push(TraitItem::Method(TraitItemMethod {
+        items.push(TraitItem::Fn(TraitItemFn {
             sig: turbo_fn.trait_signature(),
             default,
             attrs: attrs.clone(),


Reviews:
user: login: bgw
body: [![beautiful](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/WjlTemxb6oA4PgZFmj08/4a252290-d406-4b14-92e6-eeb50cb1c7d4/beautiful.gif)](https://app.graphite.dev//settings/meme-library?org=vercel)
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-21T22:37:33Z
user: login: kdy1
body: Looks good. It would be good to merge after resolving nitpicks
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T02:55:20Z

Review comments:
diff_hunk: @@ -32,7 +32,8 @@ impl Parse for ValueTraitArguments {
             return Ok(result);
         }
 
-        let punctuated: Punctuated<Meta, Token![,]> = input.parse_terminated(Meta::parse)?;
+        let punctuated: Punctuated<Meta, Token![,]> =
+            input.parse_terminated(Meta::parse, Token![,])?;
path: turbopack/crates/turbo-tasks-macros-shared/src/value_trait_arguments.rs
user: login: bgw
body: ```suggestion
        let punctuated = input.parse_terminated(Meta::parse, Token![,])?;
```

Nit: Let's get rid of this annotation as well, like you did for `primitive_input`? Doesn't seem to be very useful anymore.
created_at: 2025-04-21T22:21:16Z
author_association: MEMBER
diff_hunk: @@ -31,34 +31,49 @@ impl From<&[Attribute]> for FieldAttributes {
 
         for attr in attrs {
             if !attr
-                .path
+                .path()
                 .get_ident()
                 .map(|ident| *ident == "turbo_tasks")
                 .unwrap_or_default()
             {
                 continue;
             }
-            if let Ok(Meta::List(MetaList { nested, .. })) = attr
-                .parse_meta()
-                .map_err(|err| err.span().unwrap().error(err.to_string()).emit())
+            let nested = match attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
             {
-                for meta in nested {
-                    if let NestedMeta::Meta(Meta::Path(path)) = &meta {
-                        match path.get_ident().map(|ident| ident.to_string()).as_deref() {
-                            Some("trace_ignore") => result.trace_ignore = true,
-                            Some("debug_ignore") => result.debug_ignore = true,
-                            _ => path
+                Ok(punctuated) => punctuated,
+                Err(e) => {
+                    attr.meta
+                        .span()
+                        .unwrap()
+                        .error(format!(
+                            "expected `trace_ignore` or `debug_ignore`, got: {}",
+                            e
+                        ))
path: turbopack/crates/turbo-tasks-macros/src/derive/mod.rs
user: login: bgw
body: Nit:

```suggestion
                        .error(format!(
                            "expected `trace_ignore` or `debug_ignore`, got: {e}",
                        ))
```

A lot of older code doesn't do this as the syntax was only added in 2022 for 1.58.0: https://blog.rust-lang.org/2022/01/13/Rust-1.58.0/#captured-identifiers-in-format-strings
created_at: 2025-04-21T22:24:47Z
author_association: MEMBER
diff_hunk: @@ -109,61 +108,56 @@ impl TurboFn<'_> {
                         _ => &definition_context,
                     };
 
-                    if !attrs.is_empty() {
-                        receiver
-                            .span()
-                            .unwrap()
-                            .error(format!(
-                                "{} do not support attributes on self",
-                                definition_context.function_type(),
-                            ))
-                            .emit();
-                        return None;
-                    }
-
-                    if mutability.is_some() {
-                        receiver
-                            .span()
-                            .unwrap()
-                            .error(format!(
-                                "{} cannot take self by mutable reference, use &self or self: \
-                                 Vc<Self> instead",
-                                definition_context.function_type(),
-                            ))
-                            .emit();
-                        return None;
-                    }
+                    match self_type.as_ref() {
+                        // we allow `&Self` but not `&mut Self`
+                        syn::Type::Reference(type_reference) => {
+                            if let Some(m) = type_reference.mutability {
+                                m.span()
+                                    .unwrap()
+                                    .error(format!(
+                                        "{} cannot take self by mutable reference, use &self or \
+                                         self: Vc<Self> instead",
+                                        definition_context.function_type(),
+                                    ))
+                                    .emit();
+                                return None;
+                            }
 
-                    match &reference {
-                        None => {
-                            receiver
-                                .span()
-                                .unwrap()
-                                .error(format!(
-                                    "{} cannot take self by value, use &self or self: Vc<Self> \
-                                     instead",
-                                    definition_context.function_type(),
-                                ))
-                                .emit();
-                            return None;
+                            match type_reference.elem.as_ref() {
+                                syn::Type::Path(TypePath { qself: None, path })
+                                    if path.is_ident("Self") => {}
+                                _ => {
+                                    self_type
+                                        .span()
+                                        .unwrap()
+                                        .error(
+                                            "Unexpected `self` type, use `&self` or `self: \
+                                             Vc<Self>",
+                                        )
+                                        .emit();
+                                    return None;
+                                }
+                            }
                         }
-                        Some((_, Some(lifetime))) => {
-                            lifetime
+                        syn::Type::Path(_) => {}
+                        _ => {
+                            self_type
                                 .span()
                                 .unwrap()
-                                .error(format!(
-                                    "{} cannot take self by reference with a custom lifetime, use \
-                                     &self or self: Vc<Self> instead",
-                                    definition_context.function_type(),
-                                ))
+                                .error("Unexpected `self` type, use `&self` or `self: Vc<Self>")
                                 .emit();
                             return None;
                         }
-                        _ => {}
                     }
+                    // We don't validate that the user provided a valid
+                    // `turbo_tasks::Vc<Self>` here.
+                    // We'll rely on the compiler to emit an error
+                    // if the user provided an invalid receiver type
path: turbopack/crates/turbo-tasks-macros/src/func.rs
user: login: bgw
body: For future reference, if you're moving comments like this around, IMO it's nice to re-wrap them. Until about a year ago (https://github.com/vercel/next.js/pull/68541), we were wrapping all of our comments to 80 columns due to a bug in the default configuration of a nightly rustfmt feature... It's not easy to fix everything with a codemod (the automatic line wrapping algorithm isn't 100% safe).

If you just unwrap comments and save, your editor should re-apply wrapping when it runs rustfmt.
created_at: 2025-04-21T22:27:17Z
author_association: MEMBER
diff_hunk: @@ -109,61 +108,56 @@ impl TurboFn<'_> {
                         _ => &definition_context,
                     };
 
-                    if !attrs.is_empty() {
-                        receiver
-                            .span()
-                            .unwrap()
-                            .error(format!(
-                                "{} do not support attributes on self",
-                                definition_context.function_type(),
-                            ))
-                            .emit();
-                        return None;
-                    }
-
-                    if mutability.is_some() {
-                        receiver
-                            .span()
-                            .unwrap()
-                            .error(format!(
-                                "{} cannot take self by mutable reference, use &self or self: \
-                                 Vc<Self> instead",
-                                definition_context.function_type(),
-                            ))
-                            .emit();
-                        return None;
-                    }
+                    match self_type.as_ref() {
+                        // we allow `&Self` but not `&mut Self`
+                        syn::Type::Reference(type_reference) => {
+                            if let Some(m) = type_reference.mutability {
+                                m.span()
+                                    .unwrap()
+                                    .error(format!(
+                                        "{} cannot take self by mutable reference, use &self or \
+                                         self: Vc<Self> instead",
+                                        definition_context.function_type(),
+                                    ))
+                                    .emit();
+                                return None;
+                            }
 
-                    match &reference {
-                        None => {
-                            receiver
-                                .span()
-                                .unwrap()
-                                .error(format!(
-                                    "{} cannot take self by value, use &self or self: Vc<Self> \
-                                     instead",
-                                    definition_context.function_type(),
-                                ))
-                                .emit();
-                            return None;
+                            match type_reference.elem.as_ref() {
+                                syn::Type::Path(TypePath { qself: None, path })
+                                    if path.is_ident("Self") => {}
+                                _ => {
+                                    self_type
+                                        .span()
+                                        .unwrap()
+                                        .error(
+                                            "Unexpected `self` type, use `&self` or `self: \
+                                             Vc<Self>",
+                                        )
+                                        .emit();
+                                    return None;
+                                }
+                            }
                         }
-                        Some((_, Some(lifetime))) => {
-                            lifetime
+                        syn::Type::Path(_) => {}
+                        _ => {
+                            self_type
                                 .span()
                                 .unwrap()
-                                .error(format!(
-                                    "{} cannot take self by reference with a custom lifetime, use \
-                                     &self or self: Vc<Self> instead",
-                                    definition_context.function_type(),
-                                ))
+                                .error("Unexpected `self` type, use `&self` or `self: Vc<Self>")
                                 .emit();
                             return None;
                         }
-                        _ => {}
                     }
+                    // We don't validate that the user provided a valid
+                    // `turbo_tasks::Vc<Self>` here.
+                    // We'll rely on the compiler to emit an error
+                    // if the user provided an invalid receiver type
+
+                    let ident: Ident = self_token.clone().into();
path: turbopack/crates/turbo-tasks-macros/src/func.rs
user: login: bgw
body: Very tiny nit: Probably not everyone on the team feels the same, but I usually prefer using the `From` trait when the type isn't otherwise obvious. E.g. I tend to use `RcStr::from(...)`.

```suggestion
                    let ident = Ident::from(self_token.clone());
```
created_at: 2025-04-21T22:31:16Z
author_association: MEMBER
diff_hunk: @@ -359,83 +331,106 @@ impl TurboFn<'_> {
                 inline_inputs_identifier_filter(&pat_id.ident)
             })
             .enumerate()
-            .map(|(idx, arg)| match arg {
-                FnArg::Receiver(_) => (arg.clone(), None),
-                FnArg::Typed(pat_type) => {
-                    if self.operation {
-                        // operations shouldn't have their arguments rewritten, they require all
-                        // arguments are explicitly `NonLocalValue`s
-                        return (arg.clone(), None);
-                    }
-                    let Cow::Owned(expanded_ty) = expand_task_input_type(&pat_type.ty) else {
-                        // common-case: skip if no type conversion is needed
-                        return (arg.clone(), None);
-                    };
-
-                    let arg_id = if let Pat::Ident(pat_id) = &*pat_type.pat {
-                        // common case: argument is just an identifier
-                        Cow::Borrowed(&pat_id.ident)
-                    } else {
-                        // argument is a pattern, we need to rewrite it to a unique identifier
-                        Cow::Owned(Ident::new(
-                            &format!("arg{idx}"),
-                            pat_type.span().resolved_at(Span::mixed_site()),
-                        ))
-                    };
-
-                    let arg = FnArg::Typed(PatType {
-                        pat: Box::new(Pat::Ident(PatIdent {
-                            attrs: Vec::new(),
-                            by_ref: None,
-                            mutability: None,
-                            ident: arg_id.clone().into_owned(),
-                            subpat: None,
-                        })),
-                        ty: Box::new(expanded_ty),
-                        ..pat_type.clone()
-                    });
-
-                    // We can't shadow `self` variables, so it this argument is a `self` argument,
-                    // generate a new identifier, and rewrite the body of the function later to use
-                    // that new identifier.
-                    // NOTE: arbitrary self types aren't `FnArg::Receiver` on syn 1.x (fixed in 2.x)
-                    let transform_pat = match &*pat_type.pat {
-                        Pat::Ident(pat_id) if pat_id.ident == "self" => {
-                            let shadow_self_id = Ident::new(
-                                "turbo_tasks_self",
-                                Span::mixed_site().located_at(pat_id.ident.span()),
-                            );
-                            shadow_self = Some(shadow_self_id.clone());
-                            Pat::Ident(PatIdent {
-                                ident: shadow_self_id,
-                                ..pat_id.clone()
-                            })
-                        }
-                        pat => pat.clone(),
-                    };
-
-                    // convert an argument of type `FromTaskInput<T>::TaskInput` into `T`.
-                    // essentially, replace any instances of `Vc` with `ResolvedVc`.
-                    let orig_ty = &*pat_type.ty;
-                    let transform_stmt = Some(Stmt::Local(Local {
+            .map(|(idx, arg)| {
+                if self.operation {
+                    // operations shouldn't have their arguments rewritten, they require all
+                    // arguments are explicitly `NonLocalValue`s
+                    return (arg.clone(), None);
+                }
+                let (FnArg::Receiver(Receiver { ty, .. }) | FnArg::Typed(PatType { ty, .. })) = arg;
+                let Cow::Owned(expanded_ty) = expand_task_input_type(&ty) else {
+                    // common-case: skip if no type conversion is needed
+                    return (arg.clone(), None);
+                };
+                // Helper to produce the transform statement
+                let transform_from_task_input = |arg_id: Cow<'_, Ident>, pat: Pat| {
+                    Stmt::Local(Local {
                         attrs: Vec::new(),
                         let_token: Default::default(),
-                        pat: transform_pat,
-                        init: Some((
-                            Default::default(),
+                        pat,
+                        init: Some(LocalInit {
+                            eq_token: Default::default(),
                             // we know the argument implements `FromTaskInput` because
                             // `expand_task_input_type` returned `Cow::Owned`
-                            parse_quote_spanned! {
-                                pat_type.span() =>
-                                <#orig_ty as turbo_tasks::task::FromTaskInput>::from_task_input(
+                            expr: parse_quote_spanned! {
+                                arg.span() =>
+                                <#ty as turbo_tasks::task::FromTaskInput>::from_task_input(
                                     #arg_id
                                 )
                             },
-                        )),
+                            diverge: None,
+                        }),
                         semi_token: Default::default(),
-                    }));
+                    })
+                };
+                match arg {
+                    FnArg::Receiver(
+                        receiver @ Receiver {
+                            attrs, self_token, ..
+                        },
+                    ) => {
+                        let arg = FnArg::Receiver(Receiver {
+                            attrs: Vec::new(),
+                            mutability: None,
+                            ty: Box::new(expanded_ty),
+                            ..receiver.clone()
+                        });
 
-                    (arg, transform_stmt)
+                        // We can't shadow `self` variables, so it this argument is a `self`
+                        // argument, generate a new identifier, and rewrite
+                        // the body of the function later to use
+                        // that new identifier.
+                        // NOTE: arbitrary self types aren't `FnArg::Receiver` on syn 1.x (fixed in
+                        // 2.x)
path: turbopack/crates/turbo-tasks-macros/src/func.rs
user: login: bgw
body: ```suggestion
```
created_at: 2025-04-21T22:36:11Z
author_association: MEMBER

PR comments:
user: login: lukesandberg
created_at: 2025-04-21T18:20:04Z
body: * **#78385** <a href="https://app.graphite.dev/github/pr/vercel/next.js/78385?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a> 👈 <a href="https://app.graphite.dev/github/pr/vercel/next.js/78385?utm_source=stack-comment-view-in-graphite" target="_blank">(View in Graphite)</a>
* `canary`


<h2></h2>

This stack of pull requests is managed by <a href="https://graphite.dev?utm-source=stack-comment"><b>Graphite</b></a>. Learn more about <a href="https://stacking.dev/?utm_source=stack-comment">stacking</a>.
<!-- Current dependencies on/for this PR: -->
author_association: CONTRIBUTOR
user: login: ijjk
created_at: 2025-04-22T16:19:47Z
body: ## Tests Passed

<!-- ## Failing test suites -- >
author_association: MEMBER
user: login: ijjk
created_at: 2025-04-22T16:21:03Z
body: # Stats from current PR

<details open>
<summary><strong>Default Build</strong> (Increase detected ⚠️)</summary>

<br/>

<details>
<summary><strong>General</strong></summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| buildDuration | 22.3s | 20.1s | N/A |
| buildDurationCached | 18.9s | 16.1s | N/A |
| nodeModulesSize | 418 MB | 418 MB | N/A |
| nextStartRea..uration (ms) | 489ms | 528ms | N/A |

</details>

<details>
<summary><strong>Client Bundles (main, webpack)</strong> Overall increase ⚠️</summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| 1733-HASH.js gzip | 44.5 kB | 45 kB | ⚠️ +476 B |
| 194b18f3-HASH.js gzip | 53.8 kB | 53.8 kB | ✓ |
| 2192.HASH.js gzip | 169 B | 169 B | ✓ |
| 4719-HASH.js gzip | 5.47 kB | 5.44 kB | N/A |
| framework-HASH.js gzip | 57.4 kB | 57.4 kB | ✓ |
| main-app-HASH.js gzip | 253 B | 256 B | N/A |
| main-HASH.js gzip | 33.5 kB | 33.5 kB | N/A |
| webpack-HASH.js gzip | 1.71 kB | 1.71 kB | N/A |
| Overall change | 156 kB | 156 kB | ⚠️ +476 B |

</details>

<details>
<summary><strong>Legacy Client Bundles (polyfills)</strong></summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| polyfills-HASH.js gzip | 39.4 kB | 39.4 kB | ✓ |
| Overall change | 39.4 kB | 39.4 kB | ✓ |

</details>

<details>
<summary><strong>Client Pages</strong></summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| _app-HASH.js gzip | 193 B | 193 B | ✓ |
| _error-HASH.js gzip | 192 B | 192 B | ✓ |
| amp-HASH.js gzip | 510 B | 510 B | ✓ |
| css-HASH.js gzip | 344 B | 342 B | N/A |
| dynamic-HASH.js gzip | 1.84 kB | 1.83 kB | N/A |
| edge-ssr-HASH.js gzip | 265 B | 265 B | ✓ |
| head-HASH.js gzip | 363 B | 364 B | N/A |
| hooks-HASH.js gzip | 392 B | 391 B | N/A |
| image-HASH.js gzip | 4.69 kB | 4.67 kB | N/A |
| index-HASH.js gzip | 267 B | 267 B | ✓ |
| link-HASH.js gzip | 2.53 kB | 2.53 kB | N/A |
| routerDirect..HASH.js gzip | 328 B | 325 B | N/A |
| script-HASH.js gzip | 396 B | 396 B | ✓ |
| withRouter-HASH.js gzip | 325 B | 325 B | ✓ |
| 1afbb74e6ecf..834.css gzip | 106 B | 106 B | ✓ |
| Overall change | 2.25 kB | 2.25 kB | ✓ |

</details>

<details>
<summary><strong>Client Build Manifests</strong></summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| _buildManifest.js gzip | 750 B | 752 B | N/A |
| Overall change | 0 B | 0 B | ✓ |

</details>

<details>
<summary><strong>Rendered Page Sizes</strong></summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| index.html gzip | 523 B | 522 B | N/A |
| link.html gzip | 535 B | 538 B | N/A |
| withRouter.html gzip | 519 B | 519 B | ✓ |
| Overall change | 519 B | 519 B | ✓ |

</details>

<details>
<summary><strong>Edge SSR bundle Size</strong></summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| edge-ssr.js gzip | 136 kB | 136 kB | N/A |
| page.js gzip | 217 kB | 212 kB | N/A |
| Overall change | 0 B | 0 B | ✓ |

</details>

<details>
<summary><strong>Middleware size</strong></summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| middleware-b..fest.js gzip | 675 B | 673 B | N/A |
| middleware-r..fest.js gzip | 155 B | 157 B | N/A |
| middleware.js gzip | 32.3 kB | 32.4 kB | N/A |
| edge-runtime..pack.js gzip | 844 B | 844 B | ✓ |
| Overall change | 844 B | 844 B | ✓ |

</details>

<details>
<summary><strong>Next Runtimes</strong></summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| app-page-exp...dev.js gzip | 314 kB | 314 kB | ✓ |
| app-page-exp..prod.js gzip | 144 kB | 144 kB | ✓ |
| app-page-tur...dev.js gzip | 314 kB | 314 kB | ✓ |
| app-page-tur..prod.js gzip | 144 kB | 144 kB | ✓ |
| app-page-tur...dev.js gzip | 305 kB | 305 kB | ✓ |
| app-page-tur..prod.js gzip | 140 kB | 140 kB | ✓ |
| app-page.run...dev.js gzip | 305 kB | 305 kB | ✓ |
| app-page.run..prod.js gzip | 140 kB | 140 kB | ✓ |
| app-route-ex...dev.js gzip | 40.7 kB | 40.7 kB | ✓ |
| app-route-ex..prod.js gzip | 26.3 kB | 26.3 kB | ✓ |
| app-route-tu...dev.js gzip | 40.7 kB | 40.7 kB | ✓ |
| app-route-tu..prod.js gzip | 26.3 kB | 26.3 kB | ✓ |
| app-route-tu...dev.js gzip | 40 kB | 40 kB | ✓ |
| app-route-tu..prod.js gzip | 26 kB | 26 kB | ✓ |
| app-route.ru...dev.js gzip | 40 kB | 40 kB | ✓ |
| app-route.ru..prod.js gzip | 26 kB | 26 kB | ✓ |
| dist_client_...dev.js gzip | 356 B | 356 B | ✓ |
| dist_client_...dev.js gzip | 359 B | 359 B | ✓ |
| dist_client_...dev.js gzip | 351 B | 351 B | ✓ |
| dist_client_...dev.js gzip | 349 B | 349 B | ✓ |
| pages-api-tu...dev.js gzip | 12 kB | 12 kB | ✓ |
| pages-api-tu..prod.js gzip | 9.83 kB | 9.83 kB | ✓ |
| pages-api.ru...dev.js gzip | 12 kB | 12 kB | ✓ |
| pages-api.ru..prod.js gzip | 9.82 kB | 9.82 kB | ✓ |
| pages-turbo....dev.js gzip | 31.4 kB | 31.4 kB | ✓ |
| pages-turbo...prod.js gzip | 21.9 kB | 21.9 kB | ✓ |
| pages.runtim...dev.js gzip | 31.6 kB | 31.6 kB | ✓ |
| pages.runtim..prod.js gzip | 22 kB | 22 kB | ✓ |
| server.runti..prod.js gzip | 61.9 kB | 61.9 kB | ✓ |
| Overall change | 2.29 MB | 2.29 MB | ✓ |

</details>

<details>
<summary><strong>build cache</strong> Overall increase ⚠️</summary>

|  | vercel/next.js canary  | vercel/next.js 04-19-upgrade_to_syn2_get_the_macros_crate_building | Change |
| - | - | - | - |
| 0.pack gzip | 2.19 MB | 2.19 MB | ⚠️ +1.49 kB |
| index.pack gzip | 77.7 kB | 77.5 kB | N/A |
| Overall change | 2.19 MB | 2.19 MB | ⚠️ +1.49 kB |

</details>

<details>
<summary><strong>Diff details</strong></summary>

<details>
<summary>Diff for <strong>page.js</strong></summary>

Diff too large to display
</details>
<details>
<summary>Diff for <strong>middleware.js</strong></summary>

Diff too large to display
</details>
<details>
<summary>Diff for <strong>edge-ssr.js</strong></summary>

Diff too large to display
</details>
<details>
<summary>Diff for <strong>css-HASH.js</strong></summary>

```diff
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [9813],
   {
-    /***/ 1586: /***/ (
+    /***/ 2628: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/css",
         function () {
-          return __webpack_require__(4362);
+          return __webpack_require__(8707);
         },
       ]);
       if (false) {
@@ -18,14 +18,7 @@
       /***/
     },
 
-    /***/ 4350: /***/ (module) => {
-      // extracted by mini-css-extract-plugin
-      module.exports = { helloWorld: "css_helloWorld__aUdUq" };
-
-      /***/
-    },
-
-    /***/ 4362: /***/ (
+    /***/ 8707: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -39,7 +32,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(5640);
       /* harmony import */ var _css_module_css__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(4350);
+        __webpack_require__(9080);
       /* harmony import */ var _css_module_css__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           _css_module_css__WEBPACK_IMPORTED_MODULE_1__
@@ -58,13 +51,20 @@
 
       /***/
     },
+
+    /***/ 9080: /***/ (module) => {
+      // extracted by mini-css-extract-plugin
+      module.exports = { helloWorld: "css_helloWorld__aUdUq" };
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(1586)
+      __webpack_exec__(2628)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>dynamic-HASH.js</strong></summary>

```diff
@@ -1,17 +1,117 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [2291],
   {
-    /***/ 283: /***/ (
+    /***/ 2001: /***/ (
+      __unused_webpack_module,
+      __webpack_exports__,
+      __webpack_require__
+    ) => {
+      "use strict";
+      __webpack_require__.r(__webpack_exports__);
+      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
+        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
+        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
+        /* harmony export */
+      });
+      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
+        __webpack_require__(5640);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
+        __webpack_require__(9553);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
+        /*#__PURE__*/ __webpack_require__.n(
+          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
+        );
+
+      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
+        () =>
+          __webpack_require__
+            .e(/* import() */ 8042)
+            .then(__webpack_require__.bind(__webpack_require__, 8042))
+            .then((mod) => mod.Hello),
+        {
+          loadableGenerated: {
+            webpack: () => [/*require.resolve*/ 8042],
+          },
+        }
+      );
+      const Page = () =>
+        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
+          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
+          {
+            children: [
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
+                children: "testing next/dynamic size",
+              }),
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
+                DynamicHello,
+                {}
+              ),
+            ],
+          }
+        );
+      var __N_SSP = true;
+      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
+
+      /***/
+    },
+
+    /***/ 2976: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/dynamic",
+        function () {
+          return __webpack_require__(2001);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7807: /***/ (
+      __unused_webpack_module,
+      exports,
+      __webpack_require__
+    ) => {
+      "use strict";
+      /* __next_internal_client_entry_do_not_use__  cjs */
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "LoadableContext", {
+        enumerable: true,
+        get: function () {
+          return LoadableContext;
+        },
+      });
+      const _interop_require_default = __webpack_require__(1532);
+      const _react = /*#__PURE__*/ _interop_require_default._(
+        __webpack_require__(148)
+      );
+      const LoadableContext = _react.default.createContext(null);
+      if (false) {
+      } //# sourceMappingURL=loadable-context.shared-runtime.js.map
+
+      /***/
+    },
+
+    /***/ 9553: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(6990);
+      module.exports = __webpack_require__(9986);
 
       /***/
     },
 
-    /***/ 505: /***/ (
+    /***/ 9829: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -53,7 +153,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
       const _react = /*#__PURE__*/ _interop_require_default._(
         __webpack_require__(148)
       );
-      const _loadablecontextsharedruntime = __webpack_require__(6179);
+      const _loadablecontextsharedruntime = __webpack_require__(7807);
       function resolve(obj) {
         return obj && obj.default ? obj.default : obj;
       }
@@ -288,90 +388,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
       /***/
     },
 
-    /***/ 5703: /***/ (
-      __unused_webpack_module,
-      __webpack_exports__,
-      __webpack_require__
-    ) => {
-      "use strict";
-      __webpack_require__.r(__webpack_exports__);
-      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
-        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
-        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
-        /* harmony export */
-      });
-      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
-        __webpack_require__(5640);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(283);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
-        /*#__PURE__*/ __webpack_require__.n(
-          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
-        );
-
-      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
-        () =>
-          __webpack_require__
-            .e(/* import() */ 2192)
-            .then(__webpack_require__.bind(__webpack_require__, 2192))
-            .then((mod) => mod.Hello),
-        {
-          loadableGenerated: {
-            webpack: () => [/*require.resolve*/ 2192],
-          },
-        }
-      );
-      const Page = () =>
-        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
-          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
-          {
-            children: [
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
-                children: "testing next/dynamic size",
-              }),
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
-                DynamicHello,
-                {}
-              ),
-            ],
-          }
-        );
-      var __N_SSP = true;
-      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
-
-      /***/
-    },
-
-    /***/ 6179: /***/ (
-      __unused_webpack_module,
-      exports,
-      __webpack_require__
-    ) => {
-      "use strict";
-      /* __next_internal_client_entry_do_not_use__  cjs */
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "LoadableContext", {
-        enumerable: true,
-        get: function () {
-          return LoadableContext;
-        },
-      });
-      const _interop_require_default = __webpack_require__(1532);
-      const _react = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(148)
-      );
-      const LoadableContext = _react.default.createContext(null);
-      if (false) {
-      } //# sourceMappingURL=loadable-context.shared-runtime.js.map
-
-      /***/
-    },
-
-    /***/ 6990: /***/ (module, exports, __webpack_require__) => {
+    /***/ 9986: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -404,7 +421,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
         __webpack_require__(148)
       );
       const _loadablesharedruntime = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(505)
+        __webpack_require__(9829)
       );
       const isServerSide = "object" === "undefined";
       // Normalize loader to return the module as form { default: Component } for `React.lazy`.
@@ -504,30 +521,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
 
       /***/
     },
-
-    /***/ 9254: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/dynamic",
-        function () {
-          return __webpack_require__(5703);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(9254)
+      __webpack_exec__(2976)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>hooks-HASH.js</strong></summary>

```diff
@@ -1,24 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [9804],
   {
-    /***/ 1664: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/hooks",
-        function () {
-          return __webpack_require__(6130);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 6130: /***/ (
+    /***/ 4756: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -76,13 +59,30 @@
 
       /***/
     },
+
+    /***/ 5426: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/hooks",
+        function () {
+          return __webpack_require__(4756);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(1664)
+      __webpack_exec__(5426)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>image-HASH.js</strong></summary>

```diff
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [2983],
   {
-    /***/ 2198: /***/ (
+    /***/ 264: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/image",
         function () {
-          return __webpack_require__(3444);
+          return __webpack_require__(3594);
         },
       ]);
       if (false) {
@@ -18,7 +18,190 @@
       /***/
     },
 
-    /***/ 2514: /***/ (
+    /***/ 1206: /***/ (__unused_webpack_module, exports) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "default", {
+        enumerable: true,
+        get: function () {
+          return _default;
+        },
+      });
+      const DEFAULT_Q = 75;
+      function defaultLoader(param) {
+        let { config, src, width, quality } = param;
+        var _config_qualities;
+        if (false) {
+        }
+        const q =
+          quality ||
+          ((_config_qualities = config.qualities) == null
+            ? void 0
+            : _config_qualities.reduce((prev, cur) =>
+                Math.abs(cur - DEFAULT_Q) < Math.abs(prev - DEFAULT_Q)
+                  ? cur
+                  : prev
+              )) ||
+          DEFAULT_Q;
+        return (
+          config.path +
+          "?url=" +
+          encodeURIComponent(src) +
+          "&w=" +
+          width +
+          "&q=" +
+          q +
+          (src.startsWith("/_next/static/media/") && false ? 0 : "")
+        );
+      }
+      // We use this to determine if the import is the default loader
+      // or a custom loader defined by the user in next.config.js
+      defaultLoader.__next_img_default = true;
+      const _default = defaultLoader; //# sourceMappingURL=image-loader.js.map
+
+      /***/
+    },
+
+    /***/ 1765: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useMergedRef", {
+        enumerable: true,
+        get: function () {
+          return useMergedRef;
+        },
+      });
+      const _react = __webpack_require__(148);
+      function useMergedRef(refA, refB) {
+        const cleanupA = (0, _react.useRef)(null);
+        const cleanupB = (0, _react.useRef)(null);
+        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
+        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
+        // But this can cause us to leak a cleanup-ref into user code (e.g. via `<Link legacyBehavior>`),
+        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
+        // (because it hasn't been updated for React 19)
+        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
+        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
+        return (0, _react.useCallback)(
+          (current) => {
+            if (current === null) {
+              const cleanupFnA = cleanupA.current;
+              if (cleanupFnA) {
+                cleanupA.current = null;
+                cleanupFnA();
+              }
+              const cleanupFnB = cleanupB.current;
+              if (cleanupFnB) {
+                cleanupB.current = null;
+                cleanupFnB();
+              }
+            } else {
+              if (refA) {
+                cleanupA.current = applyRef(refA, current);
+              }
+              if (refB) {
+                cleanupB.current = applyRef(refB, current);
+              }
+            }
+          },
+          [refA, refB]
+        );
+      }
+      function applyRef(refA, current) {
+        if (typeof refA === "function") {
+          const cleanup = refA(current);
+          if (typeof cleanup === "function") {
+            return cleanup;
+          } else {
+            return () => refA(null);
+          }
+        } else {
+          refA.current = current;
+          return () => {
+            refA.current = null;
+          };
+        }
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-merged-ref.js.map
+
+      /***/
+    },
+
+    /***/ 3353: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(5526);
+
+      /***/
+    },
+
+    /***/ 3594: /***/ (
+      __unused_webpack_module,
+      __webpack_exports__,
+      __webpack_require__
+    ) => {
+      "use strict";
+      // ESM COMPAT FLAG
+      __webpack_require__.r(__webpack_exports__);
+
+      // EXPORTS
+      __webpack_require__.d(__webpack_exports__, {
+        __N_SSP: () => /* binding */ __N_SSP,
+        default: () => /* binding */ pages_image,
+      });
+
+      // EXTERNAL MODULE: ./node_modules/.pnpm/react@19.1.0/node_modules/react/jsx-runtime.js
+      var jsx_runtime = __webpack_require__(5640);
+      // EXTERNAL MODULE: ./node_modules/.pnpm/next@file+..+diff-repo+packages+next+next-packed.tgz_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/next/image.js
+      var next_image = __webpack_require__(3353);
+      var image_default = /*#__PURE__*/ __webpack_require__.n(next_image); // ./pages/nextjs.png
+      /* harmony default export */ const nextjs = {
+        src: "/_next/static/media/nextjs.cae0b805.png",
+        height: 1347,
+        width: 1626,
+        blurDataURL:
+          "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAHCAMAAAACh/xsAAAAD1BMVEX////x8fH6+vrb29vo6Oh8o70bAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAH0lEQVR4nGNgwARMjIyMjCAGCzMzMwsTRISJCcRABwAEcAAkLCQfgAAAAABJRU5ErkJggg==",
+        blurWidth: 8,
+        blurHeight: 7,
+      }; // ./pages/image.js
+      function ImagePage(props) {
+        return /*#__PURE__*/ (0, jsx_runtime.jsxs)(jsx_runtime.Fragment, {
+          children: [
+            /*#__PURE__*/ (0, jsx_runtime.jsx)("h1", {
+              children: "next/image example",
+            }),
+            /*#__PURE__*/ (0, jsx_runtime.jsx)(image_default(), {
+              src: nextjs,
+              placeholder: "blur",
+            }),
+          ],
+        });
+      }
+      var __N_SSP = true;
+      /* harmony default export */ const pages_image = ImagePage;
+
+      /***/
+    },
+
+    /***/ 3854: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -34,9 +217,9 @@
           return getImgProps;
         },
       });
-      const _warnonce = __webpack_require__(5127);
-      const _imageblursvg = __webpack_require__(4287);
-      const _imageconfig = __webpack_require__(2795);
+      const _warnonce = __webpack_require__(3603);
+      const _imageblursvg = __webpack_require__(7835);
+      const _imageconfig = __webpack_require__(6799);
       const VALID_LOADING_VALUES =
         /* unused pure expression or super */ null && [
           "lazy",
@@ -463,55 +646,69 @@
       /***/
     },
 
-    /***/ 3444: /***/ (
+    /***/ 5526: /***/ (
       __unused_webpack_module,
-      __webpack_exports__,
+      exports,
       __webpack_require__
     ) => {
       "use strict";
-      // ESM COMPAT FLAG
-      __webpack_require__.r(__webpack_exports__);
 
-      // EXPORTS
-      __webpack_require__.d(__webpack_exports__, {
-        __N_SSP: () => /* binding */ __N_SSP,
-        default: () => /* binding */ pages_image,
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
       });
-
-      // EXTERNAL MODULE: ./node_modules/.pnpm/react@19.1.0/node_modules/react/jsx-runtime.js
-      var jsx_runtime = __webpack_require__(5640);
-      // EXTERNAL MODULE: ./node_modules/.pnpm/next@file+..+main-repo+packages+next+next-packed.tgz_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/next/image.js
-      var next_image = __webpack_require__(6359);
-      var image_default = /*#__PURE__*/ __webpack_require__.n(next_image); // ./pages/nextjs.png
-      /* harmony default export */ const nextjs = {
-        src: "/_next/static/media/nextjs.cae0b805.png",
-        height: 1347,
-        width: 1626,
-        blurDataURL:
-          "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAHCAMAAAACh/xsAAAAD1BMVEX////x8fH6+vrb29vo6Oh8o70bAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAH0lEQVR4nGNgwARMjIyMjCAGCzMzMwsTRISJCcRABwAEcAAkLCQfgAAAAABJRU5ErkJggg==",
-        blurWidth: 8,
-        blurHeight: 7,
-      }; // ./pages/image.js
-      function ImagePage(props) {
-        return /*#__PURE__*/ (0, jsx_runtime.jsxs)(jsx_runtime.Fragment, {
-          children: [
-            /*#__PURE__*/ (0, jsx_runtime.jsx)("h1", {
-              children: "next/image example",
-            }),
-            /*#__PURE__*/ (0, jsx_runtime.jsx)(image_default(), {
-              src: nextjs,
-              placeholder: "blur",
-            }),
-          ],
+      0 && 0;
+      function _export(target, all) {
+        for (var name in all)
+          Object.defineProperty(target, name, {
+            enumerable: true,
+            get: all[name],
+          });
+      }
+      _export(exports, {
+        default: function () {
+          return _default;
+        },
+        getImageProps: function () {
+          return getImageProps;
+        },
+      });
+      const _interop_require_default = __webpack_require__(1532);
+      const _getimgprops = __webpack_require__(3854);
+      const _imagecomponent = __webpack_require__(8350);
+      const _imageloader = /*#__PURE__*/ _interop_require_default._(
+        __webpack_require__(1206)
+      );
+      function getImageProps(imgProps) {
+        const { props } = (0, _getimgprops.getImgProps)(imgProps, {
+          defaultLoader: _imageloader.default,
+          // This is replaced by webpack define plugin
+          imgConf: {
+            deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
+            imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
+            path: "/_next/image",
+            loader: "default",
+            dangerouslyAllowSVG: false,
+            unoptimized: false,
+          },
         });
+        // Normally we don't care about undefined props because we pass to JSX,
+        // but this exported function could be used by the end user for anything
+        // so we delete undefined props to clean it up a little.
+        for (const [key, value] of Object.entries(props)) {
+          if (value === undefined) {
+            delete props[key];
+          }
+        }
+        return {
+          props,
+        };
       }
-      var __N_SSP = true;
-      /* harmony default export */ const pages_image = ImagePage;
+      const _default = _imagecomponent.Image; //# sourceMappingURL=image-external.js.map
 
       /***/
     },
 
-    /***/ 4287: /***/ (__unused_webpack_module, exports) => {
+    /***/ 7835: /***/ (__unused_webpack_module, exports) => {
       "use strict";
       /**
        * A shared function, used on both client and server, to generate a SVG blur placeholder.
@@ -566,85 +763,7 @@
       /***/
     },
 
-    /***/ 4985: /***/ (module, exports, __webpack_require__) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "useMergedRef", {
-        enumerable: true,
-        get: function () {
-          return useMergedRef;
-        },
-      });
-      const _react = __webpack_require__(148);
-      function useMergedRef(refA, refB) {
-        const cleanupA = (0, _react.useRef)(null);
-        const cleanupB = (0, _react.useRef)(null);
-        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
-        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
-        // But this can cause us to leak a cleanup-ref into user code (e.g. via `<Link legacyBehavior>`),
-        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
-        // (because it hasn't been updated for React 19)
-        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
-        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
-        return (0, _react.useCallback)(
-          (current) => {
-            if (current === null) {
-              const cleanupFnA = cleanupA.current;
-              if (cleanupFnA) {
-                cleanupA.current = null;
-                cleanupFnA();
-              }
-              const cleanupFnB = cleanupB.current;
-              if (cleanupFnB) {
-                cleanupB.current = null;
-                cleanupFnB();
-              }
-            } else {
-              if (refA) {
-                cleanupA.current = applyRef(refA, current);
-              }
-              if (refB) {
-                cleanupB.current = applyRef(refB, current);
-              }
-            }
-          },
-          [refA, refB]
-        );
-      }
-      function applyRef(refA, current) {
-        if (typeof refA === "function") {
-          const cleanup = refA(current);
-          if (typeof cleanup === "function") {
-            return cleanup;
-          } else {
-            return () => refA(null);
-          }
-        } else {
-          refA.current = current;
-          return () => {
-            refA.current = null;
-          };
-        }
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-merged-ref.js.map
-
-      /***/
-    },
-
-    /***/ 5898: /***/ (module, exports, __webpack_require__) => {
+    /***/ 8350: /***/ (module, exports, __webpack_require__) => {
       "use strict";
       /* __next_internal_client_entry_do_not_use__  cjs */
       Object.defineProperty(exports, "__esModule", {
@@ -666,17 +785,17 @@
         __webpack_require__(7897)
       );
       const _head = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(5207)
+        __webpack_require__(8843)
       );
-      const _getimgprops = __webpack_require__(2514);
-      const _imageconfig = __webpack_require__(2795);
-      const _imageconfigcontextsharedruntime = __webpack_require__(2349);
-      const _warnonce = __webpack_require__(5127);
-      const _routercontextsharedruntime = __webpack_require__(3556);
+      const _getimgprops = __webpack_require__(3854);
+      const _imageconfig = __webpack_require__(6799);
+      const _imageconfigcontextsharedruntime = __webpack_require__(3905);
+      const _warnonce = __webpack_require__(3603);
+      const _routercontextsharedruntime = __webpack_require__(6712);
       const _imageloader = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(5970)
+        __webpack_require__(1206)
       );
-      const _usemergedref = __webpack_require__(4985);
+      const _usemergedref = __webpack_require__(1765);
       // This is replaced by webpack define plugin
       const configEnv = {
         deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
@@ -1002,132 +1121,13 @@
 
       /***/
     },
-
-    /***/ 5970: /***/ (__unused_webpack_module, exports) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "default", {
-        enumerable: true,
-        get: function () {
-          return _default;
-        },
-      });
-      const DEFAULT_Q = 75;
-      function defaultLoader(param) {
-        let { config, src, width, quality } = param;
-        var _config_qualities;
-        if (false) {
-        }
-        const q =
-          quality ||
-          ((_config_qualities = config.qualities) == null
-            ? void 0
-            : _config_qualities.reduce((prev, cur) =>
-                Math.abs(cur - DEFAULT_Q) < Math.abs(prev - DEFAULT_Q)
-                  ? cur
-                  : prev
-              )) ||
-          DEFAULT_Q;
-        return (
-          config.path +
-          "?url=" +
-          encodeURIComponent(src) +
-          "&w=" +
-          width +
-          "&q=" +
-          q +
-          (src.startsWith("/_next/static/media/") && false ? 0 : "")
-        );
-      }
-      // We use this to determine if the import is the default loader
-      // or a custom loader defined by the user in next.config.js
-      defaultLoader.__next_img_default = true;
-      const _default = defaultLoader; //# sourceMappingURL=image-loader.js.map
-
-      /***/
-    },
-
-    /***/ 6359: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(8986);
-
-      /***/
-    },
-
-    /***/ 8986: /***/ (
-      __unused_webpack_module,
-      exports,
-      __webpack_require__
-    ) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      0 && 0;
-      function _export(target, all) {
-        for (var name in all)
-          Object.defineProperty(target, name, {
-            enumerable: true,
-            get: all[name],
-          });
-      }
-      _export(exports, {
-        default: function () {
-          return _default;
-        },
-        getImageProps: function () {
-          return getImageProps;
-        },
-      });
-      const _interop_require_default = __webpack_require__(1532);
-      const _getimgprops = __webpack_require__(2514);
-      const _imagecomponent = __webpack_require__(5898);
-      const _imageloader = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(5970)
-      );
-      function getImageProps(imgProps) {
-        const { props } = (0, _getimgprops.getImgProps)(imgProps, {
-          defaultLoader: _imageloader.default,
-          // This is replaced by webpack define plugin
-          imgConf: {
-            deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
-            imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
-            path: "/_next/image",
-            loader: "default",
-            dangerouslyAllowSVG: false,
-            unoptimized: false,
-          },
-        });
-        // Normally we don't care about undefined props because we pass to JSX,
-        // but this exported function could be used by the end user for anything
-        // so we delete undefined props to clean it up a little.
-        for (const [key, value] of Object.entries(props)) {
-          if (value === undefined) {
-            delete props[key];
-          }
-        }
-        return {
-          props,
-        };
-      }
-      const _default = _imagecomponent.Image; //# sourceMappingURL=image-external.js.map
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2198)
+      __webpack_exec__(264)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>index-HASH.js</strong></summary>

```diff
@@ -1,7 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3332],
   {
-    /***/ 9418: /***/ (
+    /***/ 8230: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/",
+        function () {
+          return __webpack_require__(8696);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 8696: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -19,30 +36,13 @@
 
       /***/
     },
-
-    /***/ 9532: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/",
-        function () {
-          return __webpack_require__(9418);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(9532)
+      __webpack_exec__(8230)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>link-HASH.js</strong></summary>

```diff
@@ -1,125 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [4672],
   {
-    /***/ 1854: /***/ (
-      __unused_webpack_module,
-      __webpack_exports__,
-      __webpack_require__
-    ) => {
-      "use strict";
-      __webpack_require__.r(__webpack_exports__);
-      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
-        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
-        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
-        /* harmony export */
-      });
-      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
-        __webpack_require__(5640);
-      /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(8770);
-      /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default =
-        /*#__PURE__*/ __webpack_require__.n(
-          next_link__WEBPACK_IMPORTED_MODULE_1__
-        );
-
-      function aLink(props) {
-        return /*#__PURE__*/ (0,
-        react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
-          children: [
-            /*#__PURE__*/ (0,
-            react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", {
-              children: "A Link page!",
-            }),
-            /*#__PURE__*/ (0,
-            react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
-              next_link__WEBPACK_IMPORTED_MODULE_1___default(),
-              {
-                href: "/",
-                children: "Go to /",
-              }
-            ),
-          ],
-        });
-      }
-      var __N_SSP = true;
-      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = aLink;
-
-      /***/
-    },
-
-    /***/ 3199: /***/ (__unused_webpack_module, exports) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "errorOnce", {
-        enumerable: true,
-        get: function () {
-          return errorOnce;
-        },
-      });
-      let errorOnce = (_) => {};
-      if (false) {
-      } //# sourceMappingURL=error-once.js.map
-
-      /***/
-    },
-
-    /***/ 3568: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/link",
-        function () {
-          return __webpack_require__(1854);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 3857: /***/ (module, exports, __webpack_require__) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "getDomainLocale", {
-        enumerable: true,
-        get: function () {
-          return getDomainLocale;
-        },
-      });
-      const _normalizetrailingslash = __webpack_require__(4869);
-      const basePath =
-        /* unused pure expression or super */ null && (false || "");
-      function getDomainLocale(path, locale, locales, domainLocales) {
-        if (false) {
-        } else {
-          return false;
-        }
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=get-domain-locale.js.map
-
-      /***/
-    },
-
-    /***/ 3947: /***/ (module, exports, __webpack_require__) => {
+    /***/ 591: /***/ (module, exports, __webpack_require__) => {
       "use strict";
       /* __next_internal_client_entry_do_not_use__  cjs */
       Object.defineProperty(exports, "__esModule", {
@@ -146,17 +28,17 @@
       const _react = /*#__PURE__*/ _interop_require_wildcard._(
         __webpack_require__(148)
       );
-      const _resolvehref = __webpack_require__(3161);
-      const _islocalurl = __webpack_require__(2309);
-      const _formaturl = __webpack_require__(3768);
-      const _utils = __webpack_require__(5554);
-      const _addlocale = __webpack_require__(7591);
-      const _routercontextsharedruntime = __webpack_require__(3556);
-      const _useintersection = __webpack_require__(5624);
-      const _getdomainlocale = __webpack_require__(3857);
-      const _addbasepath = __webpack_require__(4356);
-      const _usemergedref = __webpack_require__(4985);
-      const _erroronce = __webpack_require__(3199);
+      const _resolvehref = __webpack_require__(5837);
+      const _islocalurl = __webpack_require__(5953);
+      const _formaturl = __webpack_require__(6212);
+      const _utils = __webpack_require__(6950);
+      const _addlocale = __webpack_require__(6467);
+      const _routercontextsharedruntime = __webpack_require__(6712);
+      const _useintersection = __webpack_require__(9692);
+      const _getdomainlocale = __webpack_require__(6850);
+      const _addbasepath = __webpack_require__(4928);
+      const _usemergedref = __webpack_require__(1765);
+      const _erroronce = __webpack_require__(8659);
       const prefetched = new Set();
       function prefetch(router, href, as, options) {
         if (false) {
@@ -545,7 +427,17 @@
       /***/
     },
 
-    /***/ 4985: /***/ (module, exports, __webpack_require__) => {
+    /***/ 1148: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(591);
+
+      /***/
+    },
+
+    /***/ 1765: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -623,7 +515,125 @@
       /***/
     },
 
-    /***/ 5624: /***/ (module, exports, __webpack_require__) => {
+    /***/ 5436: /***/ (
+      __unused_webpack_module,
+      __webpack_exports__,
+      __webpack_require__
+    ) => {
+      "use strict";
+      __webpack_require__.r(__webpack_exports__);
+      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
+        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
+        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
+        /* harmony export */
+      });
+      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
+        __webpack_require__(5640);
+      /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ =
+        __webpack_require__(1148);
+      /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default =
+        /*#__PURE__*/ __webpack_require__.n(
+          next_link__WEBPACK_IMPORTED_MODULE_1__
+        );
+
+      function aLink(props) {
+        return /*#__PURE__*/ (0,
+        react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
+          children: [
+            /*#__PURE__*/ (0,
+            react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", {
+              children: "A Link page!",
+            }),
+            /*#__PURE__*/ (0,
+            react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
+              next_link__WEBPACK_IMPORTED_MODULE_1___default(),
+              {
+                href: "/",
+                children: "Go to /",
+              }
+            ),
+          ],
+        });
+      }
+      var __N_SSP = true;
+      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = aLink;
+
+      /***/
+    },
+
+    /***/ 6850: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "getDomainLocale", {
+        enumerable: true,
+        get: function () {
+          return getDomainLocale;
+        },
+      });
+      const _normalizetrailingslash = __webpack_require__(6457);
+      const basePath =
+        /* unused pure expression or super */ null && (false || "");
+      function getDomainLocale(path, locale, locales, domainLocales) {
+        if (false) {
+        } else {
+          return false;
+        }
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=get-domain-locale.js.map
+
+      /***/
+    },
+
+    /***/ 8659: /***/ (__unused_webpack_module, exports) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "errorOnce", {
+        enumerable: true,
+        get: function () {
+          return errorOnce;
+        },
+      });
+      let errorOnce = (_) => {};
+      if (false) {
+      } //# sourceMappingURL=error-once.js.map
+
+      /***/
+    },
+
+    /***/ 9666: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/link",
+        function () {
+          return __webpack_require__(5436);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 9692: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -636,7 +646,7 @@
         },
       });
       const _react = __webpack_require__(148);
-      const _requestidlecallback = __webpack_require__(3543);
+      const _requestidlecallback = __webpack_require__(315);
       const hasIntersectionObserver =
         typeof IntersectionObserver === "function";
       const observers = new Map();
@@ -748,23 +758,13 @@
 
       /***/
     },
-
-    /***/ 8770: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(3947);
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(3568)
+      __webpack_exec__(9666)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>routerDirect-HASH.js</strong></summary>

```diff
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [188],
   {
-    /***/ 3618: /***/ (
+    /***/ 76: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -16,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(5640);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(4631);
+        __webpack_require__(9413);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -36,17 +36,7 @@
       /***/
     },
 
-    /***/ 4631: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(7086);
-
-      /***/
-    },
-
-    /***/ 7824: /***/ (
+    /***/ 1810: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -54,7 +44,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/routerDirect",
         function () {
-          return __webpack_require__(3618);
+          return __webpack_require__(76);
         },
       ]);
       if (false) {
@@ -62,13 +52,23 @@
 
       /***/
     },
+
+    /***/ 9413: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(5282);
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(7824)
+      __webpack_exec__(1810)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>script-HASH.js</strong></summary>

```diff
@@ -1,24 +1,17 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [1209],
   {
-    /***/ 1984: /***/ (
-      __unused_webpack_module,
+    /***/ 2227: /***/ (
+      module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/script",
-        function () {
-          return __webpack_require__(5769);
-        },
-      ]);
-      if (false) {
-      }
+      module.exports = __webpack_require__(5984);
 
       /***/
     },
 
-    /***/ 5769: /***/ (
+    /***/ 3043: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -33,7 +26,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(5640);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(8293);
+        __webpack_require__(2227);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_script__WEBPACK_IMPORTED_MODULE_1__
@@ -66,12 +59,19 @@
       /***/
     },
 
-    /***/ 8293: /***/ (
-      module,
+    /***/ 3642: /***/ (
+      __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(900);
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/script",
+        function () {
+          return __webpack_require__(3043);
+        },
+      ]);
+      if (false) {
+      }
 
       /***/
     },
@@ -81,7 +81,7 @@
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(1984)
+      __webpack_exec__(3642)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>withRouter-HASH.js</strong></summary>

```diff
@@ -1,34 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3263],
   {
-    /***/ 4631: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(7086);
-
-      /***/
-    },
-
-    /***/ 9216: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/withRouter",
-        function () {
-          return __webpack_require__(9803);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 9803: /***/ (
+    /***/ 1089: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(5640);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(4631);
+        __webpack_require__(9413);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -61,13 +34,40 @@
 
       /***/
     },
+
+    /***/ 3962: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/withRouter",
+        function () {
+          return __webpack_require__(1089);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 9413: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(5282);
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(9216)
+      __webpack_exec__(3962)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
```
</details>
<details>
<summary>Diff for <strong>1733-HASH.js</strong></summary>

Diff too large to display
</details>
<details>
<summary>Diff for <strong>4719-HASH.js</strong></summary>

Diff too large to display
</details>
<details>
<summary>Diff for <strong>main-HASH.js</strong></summary>

Diff too large to display
</details>

</details>

</details>
Commit: fa691f7e31724c6d598ecc61355afc5aa91270fb
author_association: MEMBER
user: login: mischnic
created_at: 2025-04-23T08:54:37Z
body: Looks like some unit test error snapshot is outdated
author_association: MEMBER
user: login: lukesandberg
created_at: 2025-04-23T17:26:45Z
body: yeah there is some delta between my local runs and CI.  Apparently this is related to our `config.toml` file, see https://github.com/dtolnay/trybuild/issues/290.  Bumping the version should address.
author_association: CONTRIBUTOR