@@ -12,6 +12,7 @@ use quote::ToTokens;
12
12
use syn:: ext:: IdentExt ;
13
13
use syn:: parse:: { Parse , ParseStream , Result as SynResult } ;
14
14
use syn:: spanned:: Spanned ;
15
+ use syn:: visit_mut:: VisitMut ;
15
16
use syn:: { ItemFn , Lit , MacroDelimiter , ReturnType } ;
16
17
17
18
use crate :: ClassMarker ;
@@ -912,26 +913,33 @@ fn function_from_decl(
912
913
913
914
let syn:: Signature { inputs, output, .. } = sig;
914
915
915
- let replace_self = |t : syn:: Type | {
916
- let self_ty = match self_ty {
917
- Some ( i) => i,
918
- None => return t,
919
- } ;
920
- let path = match get_ty ( & t) {
921
- syn:: Type :: Path ( syn:: TypePath { qself : None , path } ) => path. clone ( ) ,
922
- other => return other. clone ( ) ,
923
- } ;
924
- let new_path = if path. segments . len ( ) == 1 && path. segments [ 0 ] . ident == "Self" {
925
- self_ty. clone ( ) . into ( )
926
- } else {
927
- path
928
- } ;
929
- syn:: Type :: Path ( syn:: TypePath {
930
- qself : None ,
931
- path : new_path,
932
- } )
916
+ // A helper function to replace `Self` in the function signature of methods.
917
+ // E.g. `fn get(&self) -> Option<Self>` to `fn get(&self) -> Option<MyType>`
918
+ // The following comment explains why this is necessary:
919
+ // https://github.com/rustwasm/wasm-bindgen/issues/3105#issuecomment-1275160744
920
+ let replace_self = |mut t : syn:: Type | {
921
+ if let Some ( self_ty) = self_ty {
922
+ // This uses a visitor to replace all occurrences of `Self` with
923
+ // the actual type identifier. The visitor guarantees that we find
924
+ // all occurrences of `Self`, even if deeply nested and even if
925
+ // future Rust versions add more places where `Self` can appear.
926
+ struct SelfReplace ( Ident ) ;
927
+ impl VisitMut for SelfReplace {
928
+ fn visit_ident_mut ( & mut self , i : & mut proc_macro2:: Ident ) {
929
+ if i == "Self" {
930
+ * i = self . 0 . clone ( ) ;
931
+ }
932
+ }
933
+ }
934
+
935
+ let mut replace = SelfReplace ( self_ty. clone ( ) ) ;
936
+ replace. visit_type_mut ( & mut t) ;
937
+ }
938
+ t
933
939
} ;
934
940
941
+ // A helper function to replace argument names that are JS keywords.
942
+ // E.g. this will replace `fn foo(class: u32)` to `fn foo(_class: u32)`
935
943
let replace_colliding_arg = |i : & mut syn:: PatType | {
936
944
if let syn:: Pat :: Ident ( ref mut i) = * i. pat {
937
945
let ident = i. ident . to_string ( ) ;
@@ -946,14 +954,18 @@ fn function_from_decl(
946
954
. into_iter ( )
947
955
. filter_map ( |arg| match arg {
948
956
syn:: FnArg :: Typed ( mut c) => {
957
+ // typical arguments like foo: u32
949
958
replace_colliding_arg ( & mut c) ;
950
959
c. ty = Box :: new ( replace_self ( * c. ty ) ) ;
951
960
Some ( c)
952
961
}
953
962
syn:: FnArg :: Receiver ( r) => {
963
+ // the self argument, so self, &self, &mut self, self: Box<Self>, etc.
954
964
if !allow_self {
955
965
panic ! ( "arguments cannot be `self`" )
956
966
}
967
+
968
+ // write down the way in which `self` is passed for later
957
969
assert ! ( method_self. is_none( ) ) ;
958
970
if r. reference . is_none ( ) {
959
971
method_self = Some ( ast:: MethodSelf :: ByValue ) ;
@@ -962,6 +974,7 @@ fn function_from_decl(
962
974
} else {
963
975
method_self = Some ( ast:: MethodSelf :: RefShared ) ;
964
976
}
977
+
965
978
None
966
979
}
967
980
} )
0 commit comments