Skip to content

validator: fix list and leaf type conflict checks - #512

Merged
StevenACoffman merged 2 commits into
vektah:masterfrom
LuisFigueroaG:fix/overlapping-list-nullability
Oct 21, 2026
Merged

StevenACoffman merged 2 commits into
vektah:masterfrom
LuisFigueroaG:fix/overlapping-list-nullability

Conversation

@LuisFigueroaG

@LuisFigueroaG LuisFigueroaG commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

doTypesConflict let two kinds of conflicting fields merge in OverlappingFieldsCanBeMerged:

  • List nullability. A list's non-null flag is on the same ast.Type node as its Elem, and the item type was recursed into before that flag was compared, so [Int]! merged with [Int] (and [[Int]!] with [[Int]]).
  • Leaf vs composite. The leaf check required both types to be scalars or enums, so x: Int merged with x: Item.
{ someBox { ... on A { list } ... on B { list } } }        # [Int]! vs [Int]
{ someBox { ... on A { x } ... on B { x { id } } } }       # Int vs Item

graphql-js rejects both with they return conflicting types .... Non-null and list wrappers are now compared before recursing, and a conflict is reported when either named type is a leaf (IsLeafType()), matching graphql-js's isLeafType(type1) || isLeafType(type2).

The imported graphql-js cases cover neither, so I added spec cases for both, including cases that must still merge.

I have:

  • Added tests covering the bug / feature
  • Updated any relevant documentation

doTypesConflict recursed into list item types before comparing
nullability, and the non-null flag of a list lives on the same node as
its Elem. So two fields with the same response name returning [Int]!
and [Int] (or [[Int]!] and [[Int]]) in mutually exclusive fragments were
allowed to merge, even though one can be null and the other cannot.

SameResponseShape in the spec checks non-null before list types, and
graphql-js reports this as `Fields "list" conflict because they return
conflicting types "[Int]!" and "[Int]".` Compare the non-null flags
first, at every level of the type.

The imported graphql-js cases only compare nullability on named types,
so add spec cases for a list, a nested list and a matching list.
@StevenACoffman
StevenACoffman force-pushed the fix/overlapping-list-nullability branch from 7b332c2 to 1a35feb Compare October 21, 2026 12:17
@StevenACoffman StevenACoffman changed the title validator: compare list nullability in OverlappingFieldsCanBeMerged validator: fix list and leaf type conflict checks Oct 21, 2026
doTypesConflict only reported a named-type conflict when both types
were scalars or enums, so a scalar field merged with an object field
(Int with Item) in mutually exclusive fragments. A leaf has no
subfields to compare later, so graphql-js reports a conflict when
either type is a leaf. Do the same with IsLeafType().

The imported graphql-js cases never overlap a leaf with a composite
type, so add spec cases for both orders, an enum, a list, and two
object types that must still merge.

While here, fold the list-shape checks into the non-null check and
add a doc comment adapted from graphql-js.
@StevenACoffman
StevenACoffman force-pushed the fix/overlapping-list-nullability branch from 1a35feb to 2c19a66 Compare October 21, 2026 12:20
@StevenACoffman
StevenACoffman merged commit 110c3f7 into vektah:master Oct 21, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants