@@ -733,6 +733,8 @@ impl<'db> SemanticsImpl<'db> {
733
733
Some ( it) => it,
734
734
None => return ,
735
735
} ;
736
+ let def_map = sa. resolver . def_map ( ) ;
737
+
736
738
let mut stack: SmallVec < [ _ ; 4 ] > = smallvec ! [ InFile :: new( sa. file_id, token) ] ;
737
739
let mut cache = self . expansion_info_cache . borrow_mut ( ) ;
738
740
let mut mcache = self . macro_call_cache . borrow_mut ( ) ;
@@ -764,7 +766,7 @@ impl<'db> SemanticsImpl<'db> {
764
766
while let Some ( token) = stack. pop ( ) {
765
767
self . db . unwind_if_cancelled ( ) ;
766
768
let was_not_remapped = ( || {
767
- // are we inside an attribute macro call
769
+ // First expand into attribute invocations
768
770
let containing_attribute_macro_call = self . with_ctx ( |ctx| {
769
771
token. value . parent_ancestors ( ) . filter_map ( ast:: Item :: cast) . find_map ( |item| {
770
772
if item. attrs ( ) . next ( ) . is_none ( ) {
@@ -784,53 +786,19 @@ impl<'db> SemanticsImpl<'db> {
784
786
) ;
785
787
}
786
788
787
- // or are we inside a function-like macro call
788
- if let Some ( tt) =
789
- // FIXME replace map.while_some with take_while once stable
790
- token
791
- . value
792
- . parent_ancestors ( )
793
- . map ( ast:: TokenTree :: cast)
794
- . while_some ( )
795
- . last ( )
796
- {
797
- let parent = tt. syntax ( ) . parent ( ) ?;
798
- // check for derive attribute here
799
- let macro_call = match_ast ! {
800
- match parent {
801
- ast:: MacroCall ( mcall) => mcall,
802
- // attribute we failed expansion for earlier, this might be a derive invocation
803
- // so try downmapping the token into the pseudo derive expansion
804
- // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
805
- ast:: Meta ( meta) => {
806
- let attr = meta. parent_attr( ) ?;
807
- let adt = attr. syntax( ) . parent( ) . and_then( ast:: Adt :: cast) ?;
808
- let call_id = self . with_ctx( |ctx| {
809
- let ( _, call_id, _) = ctx. attr_to_derive_macro_call(
810
- token. with_value( & adt) ,
811
- token. with_value( attr) ,
812
- ) ?;
813
- Some ( call_id)
814
- } ) ?;
815
- let file_id = call_id. as_file( ) ;
816
- return process_expansion_for_token(
817
- & mut stack,
818
- file_id,
819
- Some ( adt. into( ) ) ,
820
- token. as_ref( ) ,
821
- ) ;
822
- } ,
823
- _ => return None ,
824
- }
825
- } ;
789
+ // Then check for token trees, that means we are either in a function-like macro or
790
+ // secondary attribute inputs
791
+ let tt = token. value . parent_ancestors ( ) . map_while ( ast:: TokenTree :: cast) . last ( ) ?;
792
+ let parent = tt. syntax ( ) . parent ( ) ?;
826
793
827
- if tt. left_delimiter_token ( ) . map_or ( false , |it| it == token. value ) {
828
- return None ;
829
- }
830
- if tt. right_delimiter_token ( ) . map_or ( false , |it| it == token. value ) {
831
- return None ;
832
- }
794
+ if tt. left_delimiter_token ( ) . map_or ( false , |it| it == token. value ) {
795
+ return None ;
796
+ }
797
+ if tt. right_delimiter_token ( ) . map_or ( false , |it| it == token. value ) {
798
+ return None ;
799
+ }
833
800
801
+ if let Some ( macro_call) = ast:: MacroCall :: cast ( parent. clone ( ) ) {
834
802
let mcall = token. with_value ( macro_call) ;
835
803
let file_id = match mcache. get ( & mcall) {
836
804
Some ( & it) => it,
@@ -840,11 +808,75 @@ impl<'db> SemanticsImpl<'db> {
840
808
it
841
809
}
842
810
} ;
843
- return process_expansion_for_token ( & mut stack, file_id, None , token. as_ref ( ) ) ;
811
+ process_expansion_for_token ( & mut stack, file_id, None , token. as_ref ( ) )
812
+ } else if let Some ( meta) = ast:: Meta :: cast ( parent. clone ( ) ) {
813
+ // attribute we failed expansion for earlier, this might be a derive invocation
814
+ // or derive helper attribute
815
+ let attr = meta. parent_attr ( ) ?;
816
+
817
+ let adt = if let Some ( adt) = attr. syntax ( ) . parent ( ) . and_then ( ast:: Adt :: cast) {
818
+ // this might be a derive, or a derive helper on an ADT
819
+ let derive_call = self . with_ctx ( |ctx| {
820
+ // so try downmapping the token into the pseudo derive expansion
821
+ // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
822
+ ctx. attr_to_derive_macro_call (
823
+ token. with_value ( & adt) ,
824
+ token. with_value ( attr. clone ( ) ) ,
825
+ )
826
+ . map ( |( _, call_id, _) | call_id)
827
+ } ) ;
828
+
829
+ match derive_call {
830
+ Some ( call_id) => {
831
+ // resolved to a derive
832
+ let file_id = call_id. as_file ( ) ;
833
+ return process_expansion_for_token (
834
+ & mut stack,
835
+ file_id,
836
+ Some ( adt. into ( ) ) ,
837
+ token. as_ref ( ) ,
838
+ ) ;
839
+ }
840
+ None => Some ( adt) ,
841
+ }
842
+ } else {
843
+ // Otherwise this could be a derive helper on a variant or field
844
+ if let Some ( field) = attr. syntax ( ) . parent ( ) . and_then ( ast:: RecordField :: cast)
845
+ {
846
+ field. syntax ( ) . ancestors ( ) . take ( 4 ) . find_map ( ast:: Adt :: cast)
847
+ } else if let Some ( field) =
848
+ attr. syntax ( ) . parent ( ) . and_then ( ast:: TupleField :: cast)
849
+ {
850
+ field. syntax ( ) . ancestors ( ) . take ( 4 ) . find_map ( ast:: Adt :: cast)
851
+ } else if let Some ( variant) =
852
+ attr. syntax ( ) . parent ( ) . and_then ( ast:: Variant :: cast)
853
+ {
854
+ variant. syntax ( ) . ancestors ( ) . nth ( 2 ) . and_then ( ast:: Adt :: cast)
855
+ } else {
856
+ None
857
+ }
858
+ } ?;
859
+
860
+ // Not an attribute, nor a derive, so it's either a builtin or a derive helper
861
+ // Try to resolve to a derive helper and downmap
862
+ let attr_name = attr. path ( ) . and_then ( |it| it. as_single_name_ref ( ) ) ?. as_name ( ) ;
863
+ let id = self . db . ast_id_map ( token. file_id ) . ast_id ( & adt) ;
864
+ let helpers =
865
+ def_map. derive_helpers_in_scope ( InFile :: new ( token. file_id , id) ) ?;
866
+ let item = Some ( adt. into ( ) ) ;
867
+ let mut res = None ;
868
+ for ( _, derive) in helpers. iter ( ) . filter ( |( helper, _) | * helper == attr_name) {
869
+ res = res. or ( process_expansion_for_token (
870
+ & mut stack,
871
+ derive. as_file ( ) ,
872
+ item. clone ( ) ,
873
+ token. as_ref ( ) ,
874
+ ) ) ;
875
+ }
876
+ res
877
+ } else {
878
+ None
844
879
}
845
-
846
- // outside of a macro invocation so this is a "final" token
847
- None
848
880
} ) ( )
849
881
. is_none ( ) ;
850
882
0 commit comments