@@ -34,7 +34,12 @@ impl TokenExpander {
34
34
// FIXME switch these to ExpandResult as well
35
35
TokenExpander :: Builtin ( it) => it. expand ( db, id, tt) . into ( ) ,
36
36
TokenExpander :: BuiltinDerive ( it) => it. expand ( db, id, tt) . into ( ) ,
37
- TokenExpander :: ProcMacro ( it) => it. expand ( db, id, tt) . into ( ) ,
37
+ TokenExpander :: ProcMacro ( _) => {
38
+ // We store the result in salsa db to prevent non-determinisc behavior in
39
+ // some proc-macro implementation
40
+ // See #4315 for details
41
+ db. expand_proc_macro ( id. into ( ) ) . into ( )
42
+ }
38
43
}
39
44
}
40
45
@@ -75,6 +80,8 @@ pub trait AstDatabase: SourceDatabase {
75
80
76
81
#[ salsa:: interned]
77
82
fn intern_eager_expansion ( & self , eager : EagerCallLoc ) -> EagerMacroId ;
83
+
84
+ fn expand_proc_macro ( & self , call : MacroCallId ) -> Result < tt:: Subtree , mbe:: ExpandError > ;
78
85
}
79
86
80
87
/// This expands the given macro call, but with different arguments. This is
@@ -216,6 +223,33 @@ fn macro_expand_with_arg(
216
223
( Some ( Arc :: new ( tt) ) , err. map ( |e| format ! ( "{:?}" , e) ) )
217
224
}
218
225
226
+ pub ( crate ) fn expand_proc_macro (
227
+ db : & dyn AstDatabase ,
228
+ id : MacroCallId ,
229
+ ) -> Result < tt:: Subtree , mbe:: ExpandError > {
230
+ let lazy_id = match id {
231
+ MacroCallId :: LazyMacro ( id) => id,
232
+ MacroCallId :: EagerMacro ( _) => unreachable ! ( ) ,
233
+ } ;
234
+
235
+ let loc = db. lookup_intern_macro ( lazy_id) ;
236
+ let macro_arg = match db. macro_arg ( id) {
237
+ Some ( it) => it,
238
+ None => {
239
+ return Err (
240
+ tt:: ExpansionError :: Unknown ( "No arguments for proc-macro" . to_string ( ) ) . into ( )
241
+ )
242
+ }
243
+ } ;
244
+
245
+ let expander = match loc. def . kind {
246
+ MacroDefKind :: CustomDerive ( expander) => expander,
247
+ _ => unreachable ! ( ) ,
248
+ } ;
249
+
250
+ expander. expand ( db, lazy_id, & macro_arg. 0 )
251
+ }
252
+
219
253
pub ( crate ) fn parse_or_expand ( db : & dyn AstDatabase , file_id : HirFileId ) -> Option < SyntaxNode > {
220
254
match file_id. 0 {
221
255
HirFileIdRepr :: FileId ( file_id) => Some ( db. parse ( file_id) . tree ( ) . syntax ( ) . clone ( ) ) ,
0 commit comments