Fix overlapping fields null type regression from 072165b#4291
Merged
Conversation
The requireSameOutputTypeShape() null check in OperationValidator was incorrectly simplified in commit 072165b. When a FieldAndType set contains both null-typed entries (from unresolvable parent types) and non-null entries (from interface inline fragments), the refactored code reports a spurious FieldsConflict error instead of skipping the comparison. This breaks the benchmarkDeepAbstractConcrete JMH benchmark. https://claude.ai/code/session_01XYg9Dqneb941aStgKaZ1Em
Restore the original null-handling logic that was incorrectly simplified in 072165b. When both typeA and typeB are null (e.g., from fragments on unresolvable types), they should be treated as compatible rather than producing a spurious FieldsConflict error. https://claude.ai/code/session_01XYg9Dqneb941aStgKaZ1Em
…regression The original test used mixed null and non-null field types which correctly produces a FieldsConflict error. The fix in requireSameOutputTypeShape handles the case where both typeA and typeB are null (treating them as compatible). Updated the test to exercise this specific both-null scenario using inline fragments on an unknown type. https://claude.ai/code/session_01MZkhqChmheW6d46H4p8T7Y
2 tasks
Contributor
Test Results 336 files +1 336 suites +1 5m 8s ⏱️ +4s Results for commit fa6c75a. ± Comparison against base commit 5b63591. This pull request removes 196 and adds 181 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
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
These tests exercise the same validation paths as OverlappingFieldValidationPerformance and OverlappingFieldValidationBenchmark but assert zero errors instead of measuring performance. This ensures the overlapping fields rule does not produce false positives (e.g. from null type handling in abstract/concrete type scenarios). https://claude.ai/code/session_01MZkhqChmheW6d46H4p8T7Y
The new OverlappingFieldsCanBeMergedBenchmarkTest loads large-schema-4 resources and builds GraphQL instances, which exceeds the default 512MB Gradle test heap. Increasing maxHeapSize to 1g for all test tasks. https://claude.ai/code/session_01MZkhqChmheW6d46H4p8T7Y
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Supersedes #4289 (which had an incorrect fix and a failing test).
Fixes a regression introduced in commit 072165b ("Clean up OperationValidator") where the null-handling logic in
requireSameOutputTypeShape()was incorrectly simplified, causing thebenchmarkDeepAbstractConcreteJMH benchmark to crash with spuriousFieldsConflicterrors.Root cause
In
OperationValidator.requireSameOutputTypeShape(), the null check was simplified from a skip-on-null to an error-on-null:The
benchmarkDeepAbstractConcretebenchmark uses fragments onWhatever(a type that doesn't exist in the schema). This produces nullgraphQLTypeentries alongside non-null entries (e.g.,Abstractfrom interface inline fragments). The broken code reports'field/field/field' : returns different types 'Abstract' and 'null', which causes the benchmark'sassertTrue(errors.size() == 0)assertion to fail.Fix
When either type is null (meaning the parent type was unresolvable), skip the comparison entirely:
A null type means "we couldn't resolve this field's type" — it doesn't mean "this field has a conflicting type". Comparing a known type against an unknown type is meaningless, so we skip it.
Test plan
benchmarkDeepAbstractConcretescenario and passesOverlappingFieldsCanBeMergedTestpasshttps://claude.ai/code/session_01MZkhqChmheW6d46H4p8T7Y