Conversation
| if @static_type.kind.abstract? | ||
| @invalid_type_locations ||= {}.compare_by_identity | ||
| @invalid_type_locations[next_result_h] = [graphql_result, key, is_nn, is_from_array] | ||
| end |
There was a problem hiding this comment.
I haven't quite grokked how this value is used... could you help me understand it? Under what conditions is it assigned and populated? Under what conditions are values read from it?
There was a problem hiding this comment.
This is only used by the eager abstract-value path that bypasses PrepareObjectStep.
build_graphql_result recursively builds list results and flattens the object candidates into @all_next_objects / @all_next_results for batched type resolution. Once that happens, each placeholder result no longer tells us which parent Hash or Array contains it, its key/index, or whether that location is non-null.
For abstract values, @invalid_type_locations records that information while the placeholder is inserted:
- the parent result container
- its key or list index
- whether the value is non-null
- whether it came from a list
Later, enqueue_next_steps resolves and validates the runtime type. If type_error handles an invalid resolved type and returns normally, set_invalid_type_result uses the saved location to replace the correct value with nil or perform normal non-null propagation.
It isn't read for valid resolved types, and it is cleared after that batch has been processed. compare_by_identity is needed because these placeholders begin as empty Hashes, which would otherwise compare equal as Hash keys.
The PrepareObjectStep path doesn't need this mapping because each step already retains its parent result, key, nullability, and list-location state.
1e3f0f2 to
b152ec0
Compare
Execution::Nextvalidates the result ofSchema.resolve_type, but its callers currently assume thatSchema.type_erroralways raises.Schemas may override
type_errorto report anUnresolvedTypeErrorand return normally. In that case, execution continues using a type that isn't one of the abstract type's possible types. Nullable abstract fields aren't set tonull, non-null list items don't perform normal null propagation, and deferred list resolution may leave placeholder results behind.Abstract roots executed with
Query#run_partialshave another issue: type validation expects a field resolution step even when no field is available, causing aNoMethodErrorinstead of the intendedUnresolvedTypeError.This PR makes resolved-type validation return whether the type is valid and stops the affected execution path when
type_errorhandles the mismatch. It also:UnresolvedTypeErrorwithout a field for abstract partial roots.Tests cover immediate and lazy type resolution, abstract partial roots, non-null list elements, and batched list execution after a sibling error.