@@ -307,7 +307,7 @@ public function validateTypes() : void
307
307
$ this ->validateFields ($ type );
308
308
309
309
// Ensure objects implement the interfaces they claim to.
310
- $ this ->validateTypeInterfaces ($ type );
310
+ $ this ->validateInterfaces ($ type );
311
311
312
312
// Ensure directives are valid
313
313
$ this ->validateDirectivesAtLocation (
@@ -319,7 +319,7 @@ public function validateTypes() : void
319
319
$ this ->validateFields ($ type );
320
320
321
321
// Ensure interfaces implement the interfaces they claim to.
322
- $ this ->validateTypeInterfaces ($ type );
322
+ $ this ->validateInterfaces ($ type );
323
323
324
324
// Ensure directives are valid
325
325
$ this ->validateDirectivesAtLocation (
@@ -661,9 +661,9 @@ private function getFieldArgNode($type, $fieldName, $argName)
661
661
/**
662
662
* @param ObjectType|InterfaceType $type
663
663
*/
664
- private function validateTypeInterfaces (ImplementingType $ type )
664
+ private function validateInterfaces (ImplementingType $ type )
665
665
{
666
- $ implementedTypeNames = [];
666
+ $ ifaceTypeNames = [];
667
667
foreach ($ type ->getInterfaces () as $ iface ) {
668
668
if (! $ iface instanceof InterfaceType) {
669
669
$ this ->reportError (
@@ -676,14 +676,16 @@ private function validateTypeInterfaces(ImplementingType $type)
676
676
);
677
677
continue ;
678
678
}
679
- if (isset ($ implementedTypeNames [$ iface ->name ])) {
679
+ if (isset ($ ifaceTypeNames [$ iface ->name ])) {
680
680
$ this ->reportError (
681
681
sprintf ('Type %s can only implement %s once. ' , $ type ->name , $ iface ->name ),
682
682
$ this ->getAllImplementsInterfaceNodes ($ type , $ iface )
683
683
);
684
684
continue ;
685
685
}
686
- $ implementedTypeNames [$ iface ->name ] = true ;
686
+ $ ifaceTypeNames [$ iface ->name ] = true ;
687
+
688
+ $ this ->validateTypeImplementsAncestors ($ type , $ iface );
687
689
$ this ->validateTypeImplementsInterface ($ type , $ iface );
688
690
}
689
691
}
@@ -877,6 +879,36 @@ private function validateTypeImplementsInterface($type, $iface)
877
879
}
878
880
}
879
881
882
+ /**
883
+ * @param ObjectType|InterfaceType $type
884
+ * @param InterfaceType $iface
885
+ */
886
+ private function validateTypeImplementsAncestors (ImplementingType $ type , $ iface ) {
887
+ $ typeInterfaces = $ type ->getInterfaces ();
888
+ foreach ($ iface ->getInterfaces () as $ transitive ) {
889
+ if (!in_array ($ transitive , $ typeInterfaces )) {
890
+ $ this ->reportError (
891
+ $ transitive === $ type ?
892
+ sprintf (
893
+ "Type %s cannot implement %s because it would create a circular reference. " ,
894
+ $ type ->name ,
895
+ $ iface ->name
896
+ ) :
897
+ sprintf (
898
+ "Type %s must implement %s because it is implemented by %s. " ,
899
+ $ type ->name ,
900
+ $ transitive ->name ,
901
+ $ iface ->name
902
+ ),
903
+ array_merge (
904
+ $ this ->getAllImplementsInterfaceNodes ($ iface , $ transitive ),
905
+ $ this ->getAllImplementsInterfaceNodes ($ type , $ iface )
906
+ )
907
+ );
908
+ }
909
+ }
910
+ }
911
+
880
912
private function validateUnionMembers (UnionType $ union )
881
913
{
882
914
$ memberTypes = $ union ->getTypes ();
0 commit comments