@@ -22,32 +22,57 @@ struct FindRecursiveDirective<'s> {
22
22
impl FindRecursiveDirective < ' _ > {
23
23
fn type_definition (
24
24
& self ,
25
- seen : & mut RecursionGuard < ' _ > ,
25
+ directive_guard : & mut RecursionGuard < ' _ > ,
26
+ type_guard : & mut RecursionGuard < ' _ > ,
26
27
def : & schema:: ExtendedType ,
27
28
) -> Result < ( ) , CycleError < ast:: Directive > > {
28
29
match def {
29
30
schema:: ExtendedType :: Scalar ( scalar_type_definition) => {
30
- self . directives ( seen, & scalar_type_definition. directives ) ?;
31
+ self . directives (
32
+ directive_guard,
33
+ type_guard,
34
+ & scalar_type_definition. directives ,
35
+ ) ?;
31
36
}
32
37
schema:: ExtendedType :: Object ( object_type_definition) => {
33
- self . directives ( seen, & object_type_definition. directives ) ?;
38
+ self . directives (
39
+ directive_guard,
40
+ type_guard,
41
+ & object_type_definition. directives ,
42
+ ) ?;
34
43
}
35
44
schema:: ExtendedType :: Interface ( interface_type_definition) => {
36
- self . directives ( seen, & interface_type_definition. directives ) ?;
45
+ self . directives (
46
+ directive_guard,
47
+ type_guard,
48
+ & interface_type_definition. directives ,
49
+ ) ?;
37
50
}
38
51
schema:: ExtendedType :: Union ( union_type_definition) => {
39
- self . directives ( seen, & union_type_definition. directives ) ?;
52
+ self . directives (
53
+ directive_guard,
54
+ type_guard,
55
+ & union_type_definition. directives ,
56
+ ) ?;
40
57
}
41
58
schema:: ExtendedType :: Enum ( enum_type_definition) => {
42
- self . directives ( seen, & enum_type_definition. directives ) ?;
59
+ self . directives (
60
+ directive_guard,
61
+ type_guard,
62
+ & enum_type_definition. directives ,
63
+ ) ?;
43
64
for enum_value in enum_type_definition. values . values ( ) {
44
- self . enum_value ( seen , enum_value) ?;
65
+ self . enum_value ( directive_guard , type_guard , enum_value) ?;
45
66
}
46
67
}
47
68
schema:: ExtendedType :: InputObject ( input_type_definition) => {
48
- self . directives ( seen, & input_type_definition. directives ) ?;
69
+ self . directives (
70
+ directive_guard,
71
+ type_guard,
72
+ & input_type_definition. directives ,
73
+ ) ?;
49
74
for input_value in input_type_definition. fields . values ( ) {
50
- self . input_value ( seen , input_value) ?;
75
+ self . input_value ( directive_guard , type_guard , input_value) ?;
51
76
}
52
77
}
53
78
}
@@ -57,55 +82,69 @@ impl FindRecursiveDirective<'_> {
57
82
58
83
fn input_value (
59
84
& self ,
60
- seen : & mut RecursionGuard < ' _ > ,
85
+ directive_guard : & mut RecursionGuard < ' _ > ,
86
+ type_guard : & mut RecursionGuard < ' _ > ,
61
87
input_value : & Node < ast:: InputValueDefinition > ,
62
88
) -> Result < ( ) , CycleError < ast:: Directive > > {
63
89
for directive in & input_value. directives {
64
- self . directive ( seen , directive) ?;
90
+ self . directive ( directive_guard , type_guard , directive) ?;
65
91
}
66
92
67
93
let type_name = input_value. ty . inner_named_type ( ) ;
68
94
if let Some ( type_def) = self . schema . types . get ( type_name) {
69
- self . type_definition ( seen, type_def) ?;
95
+ if type_guard. contains ( type_def. name ( ) ) {
96
+ // input type was already processed
97
+ return Ok ( ( ) ) ;
98
+ }
99
+ if !type_def. is_built_in ( ) {
100
+ let mut new_type_guard = type_guard. push ( type_def. name ( ) ) ?;
101
+ self . type_definition ( directive_guard, & mut new_type_guard, type_def) ?;
102
+ } else {
103
+ self . type_definition ( directive_guard, type_guard, type_def) ?;
104
+ }
70
105
}
71
106
72
107
Ok ( ( ) )
73
108
}
74
109
75
110
fn enum_value (
76
111
& self ,
77
- seen : & mut RecursionGuard < ' _ > ,
112
+ directive_guard : & mut RecursionGuard < ' _ > ,
113
+ type_guard : & mut RecursionGuard < ' _ > ,
78
114
enum_value : & Node < ast:: EnumValueDefinition > ,
79
115
) -> Result < ( ) , CycleError < ast:: Directive > > {
80
116
for directive in & enum_value. directives {
81
- self . directive ( seen , directive) ?;
117
+ self . directive ( directive_guard , type_guard , directive) ?;
82
118
}
83
119
84
120
Ok ( ( ) )
85
121
}
86
122
87
123
fn directives (
88
124
& self ,
89
- seen : & mut RecursionGuard < ' _ > ,
125
+ directive_guard : & mut RecursionGuard < ' _ > ,
126
+ type_guard : & mut RecursionGuard < ' _ > ,
90
127
directives : & [ schema:: Component < ast:: Directive > ] ,
91
128
) -> Result < ( ) , CycleError < ast:: Directive > > {
92
129
for directive in directives {
93
- self . directive ( seen , directive) ?;
130
+ self . directive ( directive_guard , type_guard , directive) ?;
94
131
}
95
132
Ok ( ( ) )
96
133
}
97
134
98
135
fn directive (
99
136
& self ,
100
- seen : & mut RecursionGuard < ' _ > ,
137
+ directive_guard : & mut RecursionGuard < ' _ > ,
138
+ type_guard : & mut RecursionGuard < ' _ > ,
101
139
directive : & Node < ast:: Directive > ,
102
140
) -> Result < ( ) , CycleError < ast:: Directive > > {
103
- if !seen . contains ( & directive. name ) {
141
+ if !directive_guard . contains ( & directive. name ) {
104
142
if let Some ( def) = self . schema . directive_definitions . get ( & directive. name ) {
105
- self . directive_definition ( seen. push ( & directive. name ) ?, def)
143
+ let mut new_directive_guard = directive_guard. push ( & directive. name ) ?;
144
+ self . directive_definition ( & mut new_directive_guard, type_guard, def)
106
145
. map_err ( |error| error. trace ( directive) ) ?;
107
146
}
108
- } else if seen . first ( ) == Some ( & directive. name ) {
147
+ } else if directive_guard . first ( ) == Some ( & directive. name ) {
109
148
// Only report an error & bail out early if this is the *initial* directive.
110
149
// This prevents raising confusing errors when a directive `@b` which is not
111
150
// self-referential uses a directive `@a` that *is*. The error with `@a` should
@@ -118,11 +157,12 @@ impl FindRecursiveDirective<'_> {
118
157
119
158
fn directive_definition (
120
159
& self ,
121
- mut seen : RecursionGuard < ' _ > ,
160
+ directive_guard : & mut RecursionGuard < ' _ > ,
161
+ type_guard : & mut RecursionGuard < ' _ > ,
122
162
def : & Node < ast:: DirectiveDefinition > ,
123
163
) -> Result < ( ) , CycleError < ast:: Directive > > {
124
164
for input_value in & def. arguments {
125
- self . input_value ( & mut seen , input_value) ?;
165
+ self . input_value ( directive_guard , type_guard , input_value) ?;
126
166
}
127
167
128
168
Ok ( ( ) )
@@ -132,9 +172,15 @@ impl FindRecursiveDirective<'_> {
132
172
schema : & schema:: Schema ,
133
173
directive_def : & Node < ast:: DirectiveDefinition > ,
134
174
) -> Result < ( ) , CycleError < ast:: Directive > > {
135
- let mut recursion_stack = RecursionStack :: with_root ( directive_def. name . clone ( ) ) ;
136
- FindRecursiveDirective { schema }
137
- . directive_definition ( recursion_stack. guard ( ) , directive_def)
175
+ let mut directive_stack = RecursionStack :: with_root ( directive_def. name . clone ( ) ) ;
176
+ let mut directive_guard = directive_stack. guard ( ) ;
177
+ let mut type_stack = RecursionStack :: new ( ) ;
178
+ let mut type_guard = type_stack. guard ( ) ;
179
+ FindRecursiveDirective { schema } . directive_definition (
180
+ & mut directive_guard,
181
+ & mut type_guard,
182
+ directive_def,
183
+ )
138
184
}
139
185
}
140
186
0 commit comments