/**
  * @param ValidationContext $context
  * @param PairSet $comparedSet
  * @param $responseName
  * @param [Field, GraphQLFieldDefinition] $pair1
  * @param [Field, GraphQLFieldDefinition] $pair2
  * @return array|null
  */
 private function findConflict($responseName, array $pair1, array $pair2, ValidationContext $context, PairSet $comparedSet)
 {
     list($ast1, $def1) = $pair1;
     list($ast2, $def2) = $pair2;
     if ($ast1 === $ast2 || $comparedSet->has($ast1, $ast2)) {
         return null;
     }
     $comparedSet->add($ast1, $ast2);
     $name1 = $ast1->name->value;
     $name2 = $ast2->name->value;
     if ($name1 !== $name2) {
         return [[$responseName, "{$name1} and {$name2} are different fields"], [$ast1, $ast2]];
     }
     $type1 = isset($def1) ? $def1->getType() : null;
     $type2 = isset($def2) ? $def2->getType() : null;
     if (!$this->sameType($type1, $type2)) {
         return [[$responseName, "they return differing types {$type1} and {$type2}"], [$ast1, $ast2]];
     }
     $args1 = isset($ast1->arguments) ? $ast1->arguments : [];
     $args2 = isset($ast2->arguments) ? $ast2->arguments : [];
     if (!$this->sameNameValuePairs($args1, $args2)) {
         return [[$responseName, 'they have differing arguments'], [$ast1, $ast2]];
     }
     $directives1 = isset($ast1->directives) ? $ast1->directives : [];
     $directives2 = isset($ast2->directives) ? $ast2->directives : [];
     if (!$this->sameNameValuePairs($directives1, $directives2)) {
         return [[$responseName, 'they have differing directives'], [$ast1, $ast2]];
     }
     $selectionSet1 = isset($ast1->selectionSet) ? $ast1->selectionSet : null;
     $selectionSet2 = isset($ast2->selectionSet) ? $ast2->selectionSet : null;
     if ($selectionSet1 && $selectionSet2) {
         $visitedFragmentNames = new \ArrayObject();
         $subfieldMap = $this->collectFieldASTsAndDefs($context, $type1, $selectionSet1, $visitedFragmentNames);
         $subfieldMap = $this->collectFieldASTsAndDefs($context, $type2, $selectionSet2, $visitedFragmentNames, $subfieldMap);
         $conflicts = $this->findConflicts($subfieldMap, $context, $comparedSet);
         if (!empty($conflicts)) {
             return [[$responseName, array_map(function ($conflict) {
                 return $conflict[0];
             }, $conflicts)], array_reduce($conflicts, function ($list, $conflict) {
                 return array_merge($list, $conflict[1]);
             }, [$ast1, $ast2])];
         }
     }
 }
 /**
  * @param $parentFieldsAreMutuallyExclusive
  * @param $responseName
  * @param [FieldNode, GraphQLFieldDefinition] $pair1
  * @param [FieldNode, GraphQLFieldDefinition] $pair2
  * @param ValidationContext $context
  * @return array|null
  */
 private function findConflict($parentFieldsAreMutuallyExclusive, $responseName, array $pair1, array $pair2, ValidationContext $context)
 {
     list($parentType1, $ast1, $def1) = $pair1;
     list($parentType2, $ast2, $def2) = $pair2;
     // Not a pair.
     if ($ast1 === $ast2) {
         return null;
     }
     // Memoize, do not report the same issue twice.
     // Note: Two overlapping ASTs could be encountered both when
     // `parentFieldsAreMutuallyExclusive` is true and is false, which could
     // produce different results (when `true` being a subset of `false`).
     // However we do not need to include this piece of information when
     // memoizing since this rule visits leaf fields before their parent fields,
     // ensuring that `parentFieldsAreMutuallyExclusive` is `false` the first
     // time two overlapping fields are encountered, ensuring that the full
     // set of validation rules are always checked when necessary.
     if ($this->comparedSet->has($ast1, $ast2)) {
         return null;
     }
     $this->comparedSet->add($ast1, $ast2);
     // The return type for each field.
     $type1 = isset($def1) ? $def1->getType() : null;
     $type2 = isset($def2) ? $def2->getType() : null;
     // If it is known that two fields could not possibly apply at the same
     // time, due to the parent types, then it is safe to permit them to diverge
     // in aliased field or arguments used as they will not present any ambiguity
     // by differing.
     // It is known that two parent types could never overlap if they are
     // different Object types. Interface or Union types might overlap - if not
     // in the current state of the schema, then perhaps in some future version,
     // thus may not safely diverge.
     $fieldsAreMutuallyExclusive = $parentFieldsAreMutuallyExclusive || $parentType1 !== $parentType2 && $parentType1 instanceof ObjectType && $parentType2 instanceof ObjectType;
     if (!$fieldsAreMutuallyExclusive) {
         $name1 = $ast1->name->value;
         $name2 = $ast2->name->value;
         if ($name1 !== $name2) {
             return [[$responseName, "{$name1} and {$name2} are different fields"], [$ast1], [$ast2]];
         }
         $args1 = isset($ast1->arguments) ? $ast1->arguments : [];
         $args2 = isset($ast2->arguments) ? $ast2->arguments : [];
         if (!$this->sameArguments($args1, $args2)) {
             return [[$responseName, 'they have differing arguments'], [$ast1], [$ast2]];
         }
     }
     if ($type1 && $type2 && $this->doTypesConflict($type1, $type2)) {
         return [[$responseName, "they return conflicting types {$type1} and {$type2}"], [$ast1], [$ast2]];
     }
     $subfieldMap = $this->getSubfieldMap($ast1, $type1, $ast2, $type2, $context);
     if ($subfieldMap) {
         $conflicts = $this->findConflicts($fieldsAreMutuallyExclusive, $subfieldMap, $context);
         return $this->subfieldConflicts($conflicts, $responseName, $ast1, $ast2);
     }
     return null;
 }