Skip to content

Commit b125184

Browse files
committed
Fix null type handling to skip comparison for unresolvable types
The previous fix only handled the both-null case, but the actual benchmarkDeepAbstractConcrete scenario has mixed null and non-null types: fragments on "Whatever" (unresolvable) produce null-typed fields alongside Abstract-typed fields from interface inline fragments. A null type means the parent was unresolvable, so we should skip the comparison entirely rather than report a spurious conflict. This changes the null check from reporting an error to simply continuing, which matches the semantic that null = unknown/unresolvable = skip. The test now reproduces the exact benchmark scenario that was crashing. https://claude.ai/code/session_01MZkhqChmheW6d46H4p8T7Y
1 parent 5025d04 commit b125184

2 files changed

Lines changed: 25 additions & 14 deletions

File tree

src/main/java/graphql/validation/OperationValidator.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,9 +1242,6 @@ private boolean sameArguments(List<Argument> arguments1, @Nullable List<Argument
12421242
GraphQLType typeA = typeAOriginal;
12431243
GraphQLType typeB = fieldAndType.graphQLType;
12441244
if (typeA == null || typeB == null) {
1245-
if (typeA != typeB) {
1246-
return mkNotSameTypeError(path, fields, typeA, typeB);
1247-
}
12481245
continue;
12491246
}
12501247
while (true) {

src/test/groovy/graphql/validation/OverlappingFieldsCanBeMergedTest.groovy

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -968,22 +968,36 @@ class OverlappingFieldsCanBeMergedTest extends Specification {
968968
errorCollector.getErrors().size() == 0
969969
}
970970

971-
def "fields with null types from unresolvable parent should not produce spurious conflicts"() {
971+
def "mixed null and non-null field types from unresolvable fragments should not conflict"() {
972972
given:
973973
// Regression test for commit 072165b which changed the null-handling in requireSameOutputTypeShape.
974-
// When multiple fields have null graphQLType (e.g. from fragments on unknown types), both typeA
975-
// and typeB are null. The old code (072165b) unconditionally reported a conflict when typeB was
976-
// null, even if typeA was also null. The fix correctly treats both-null as compatible.
974+
// This reproduces the benchmarkDeepAbstractConcrete JMH benchmark scenario: the fragment spreads
975+
// on "Whatever" (which doesn't exist in the schema), so the outer "field" has null graphQLType.
976+
// After mergeSubSelections, the inner field set contains both null-typed entries (from the
977+
// unresolvable parent) and Abstract-typed entries (from the interface inline fragments).
978+
// A null type means the parent was unresolvable, so we should skip the comparison rather than
979+
// report a spurious conflict.
977980
def schema = SchemaGenerator.createdMockedSchema('''
978-
type Query { field: String }
981+
type Query { viewer: Viewer }
982+
interface Abstract { field: Abstract leaf: Int }
983+
interface Abstract1 { field: Abstract leaf: Int }
984+
interface Abstract2 { field: Abstract leaf: Int }
985+
type Concrete1 implements Abstract1 { field: Abstract leaf: Int }
986+
type Concrete2 implements Abstract2 { field: Abstract leaf: Int }
987+
type Viewer { xingId: XingId }
988+
type XingId { firstName: String! lastName: String! }
979989
''')
980-
// Both fragments spread on "Unknown" which doesn't exist in the schema, so all field
981-
// types resolve to null. The overlapping "id" fields should be treated as compatible
982-
// since both have null type.
983990
def query = '''
984-
query Test {
985-
... on Unknown { id }
986-
... on Unknown { id }
991+
fragment multiply on Whatever {
992+
field {
993+
... on Abstract1 { field { leaf } }
994+
... on Abstract2 { field { leaf } }
995+
... on Concrete1 { field { leaf } }
996+
... on Concrete2 { field { leaf } }
997+
}
998+
}
999+
query DeepAbstractConcrete {
1000+
field { ...multiply field { ...multiply } }
9871001
}
9881002
'''
9891003
when:

0 commit comments

Comments
 (0)