@@ -9,6 +9,7 @@ use syn::{
99 punctuated:: { Pair , Punctuated } ,
1010 spanned:: Spanned ,
1111 token:: Paren ,
12+ visit_mut:: VisitMut ,
1213 AngleBracketedGenericArguments , Block , Expr , ExprBlock , ExprPath , FnArg , GenericArgument ,
1314 Local , Meta , Pat , PatIdent , PatType , Path , PathArguments , PathSegment , Receiver , ReturnType ,
1415 Signature , Stmt , Token , Type , TypeGroup , TypePath , TypeTuple ,
@@ -332,6 +333,7 @@ impl TurboFn<'_> {
332333 & self ,
333334 orig_block : & ' a Block ,
334335 ) -> ( Signature , Cow < ' a , Block > ) {
336+ let mut shadow_self = None ;
335337 let ( inputs, transform_stmts) : ( Punctuated < _ , _ > , Vec < Option < _ > > ) = self
336338 . orig_signature
337339 . inputs
@@ -340,52 +342,74 @@ impl TurboFn<'_> {
340342 . map ( |( idx, arg) | match arg {
341343 FnArg :: Receiver ( _) => ( arg. clone ( ) , None ) ,
342344 FnArg :: Typed ( pat_type) => {
343- // arbitrary self types aren't `FnArg::Receiver` on syn 1.x (fixed in 2.x)
344- if let Pat :: Ident ( pat_id) = & * pat_type. pat {
345- // TODO: Support `self: ResolvedVc<Self>`
346- if pat_id. ident == "self" {
347- return ( arg. clone ( ) , None ) ;
348- }
349- }
350345 let Cow :: Owned ( expanded_ty) = expand_task_input_type ( & pat_type. ty ) else {
351346 // common-case: skip if no type conversion is needed
352347 return ( arg. clone ( ) , None ) ;
353348 } ;
354- let arg_ident = Ident :: new (
355- & format ! ( "arg{idx}" ) ,
356- pat_type. span ( ) . resolved_at ( Span :: mixed_site ( ) ) ,
357- ) ;
349+
350+ let arg_id = if let Pat :: Ident ( pat_id) = & * pat_type. pat {
351+ // common case: argument is just an identifier
352+ Cow :: Borrowed ( & pat_id. ident )
353+ } else {
354+ // argument is a pattern, we need to rewrite it to a unique identifier
355+ Cow :: Owned ( Ident :: new (
356+ & format ! ( "arg{idx}" ) ,
357+ pat_type. span ( ) . resolved_at ( Span :: mixed_site ( ) ) ,
358+ ) )
359+ } ;
360+
358361 let arg = FnArg :: Typed ( PatType {
359362 pat : Box :: new ( Pat :: Ident ( PatIdent {
360363 attrs : Vec :: new ( ) ,
361364 by_ref : None ,
362365 mutability : None ,
363- ident : arg_ident . clone ( ) ,
366+ ident : arg_id . clone ( ) . into_owned ( ) ,
364367 subpat : None ,
365368 } ) ) ,
366369 ty : Box :: new ( expanded_ty) ,
367370 ..pat_type. clone ( )
368371 } ) ;
372+
373+ // We can't shadow `self` variables, so it this argument is a `self` argument,
374+ // generate a new identifier, and rewrite the body of the function later to use
375+ // that new identifier.
376+ // NOTE: arbitrary self types aren't `FnArg::Receiver` on syn 1.x (fixed in 2.x)
377+ let transform_pat = match & * pat_type. pat {
378+ Pat :: Ident ( pat_id) if pat_id. ident == "self" => {
379+ let shadow_self_id = Ident :: new (
380+ "turbo_tasks_self" ,
381+ Span :: mixed_site ( ) . located_at ( pat_id. ident . span ( ) ) ,
382+ ) ;
383+ shadow_self = Some ( shadow_self_id. clone ( ) ) ;
384+ Pat :: Ident ( PatIdent {
385+ ident : shadow_self_id,
386+ ..pat_id. clone ( )
387+ } )
388+ }
389+ pat => pat. clone ( ) ,
390+ } ;
391+
369392 // convert an argument of type `FromTaskInput<T>::TaskInput` into `T`.
370393 // essentially, replace any instances of `Vc` with `ResolvedVc`.
371394 let orig_ty = & * pat_type. ty ;
372395 let transform_stmt = Some ( Stmt :: Local ( Local {
373396 attrs : Vec :: new ( ) ,
374397 let_token : Default :: default ( ) ,
375- pat : * pat_type . pat . clone ( ) ,
398+ pat : transform_pat ,
376399 init : Some ( (
377400 Default :: default ( ) ,
378401 // we know the argument implements `FromTaskInput` because
379402 // `expand_task_input_type` returned `Cow::Owned`
380403 parse_quote_spanned ! {
381404 pat_type. span( ) =>
382405 <#orig_ty as turbo_tasks:: task:: FromTaskInput >:: from_task_input(
383- #arg_ident
406+ #arg_id
384407 )
385408 } ,
386409 ) ) ,
387410 semi_token : Default :: default ( ) ,
388411 } ) ) ;
412+
389413 ( arg, transform_stmt)
390414 }
391415 } )
@@ -399,13 +423,24 @@ impl TurboFn<'_> {
399423 } ;
400424
401425 let inline_block = if transform_stmts. is_empty ( ) {
426+ // common case: No argument uses ResolvedVc, don't rewrite anything!
402427 Cow :: Borrowed ( orig_block)
403428 } else {
404429 let mut stmts = transform_stmts;
405430 stmts. push ( Stmt :: Expr ( Expr :: Block ( ExprBlock {
406431 attrs : Vec :: new ( ) ,
407432 label : None ,
408- block : orig_block. clone ( ) ,
433+ block : if let Some ( shadow_self) = shadow_self {
434+ // if `self` is a `ResolvedVc<Self>`, we need to rewrite references to `self`
435+ let mut block = orig_block. clone ( ) ;
436+ RewriteSelfVisitMut {
437+ self_ident : shadow_self,
438+ }
439+ . visit_block_mut ( & mut block) ;
440+ block
441+ } else {
442+ orig_block. clone ( )
443+ } ,
409444 } ) ) ) ;
410445 Cow :: Owned ( Block {
411446 brace_token : Default :: default ( ) ,
@@ -876,6 +911,26 @@ fn expand_vc_return_type(orig_output: &Type) -> Type {
876911 new_output
877912}
878913
914+ struct RewriteSelfVisitMut {
915+ self_ident : Ident ,
916+ }
917+
918+ impl VisitMut for RewriteSelfVisitMut {
919+ fn visit_ident_mut ( & mut self , ident : & mut Ident ) {
920+ if ident == "self" {
921+ let span = self . self_ident . span ( ) . located_at ( ident. span ( ) ) ;
922+ * ident = self . self_ident . clone ( ) ;
923+ ident. set_span ( span) ;
924+ }
925+ // no children to visit
926+ }
927+
928+ fn visit_item_impl_mut ( & mut self , _: & mut syn:: ItemImpl ) {
929+ // skip children of `impl`: the definition of "self" inside of an impl is different than the
930+ // parent scope's definition of "self"
931+ }
932+ }
933+
879934/// The context in which the function is being defined.
880935#[ derive( Debug , Clone , Eq , PartialEq ) ]
881936pub enum DefinitionContext {
0 commit comments