@@ -324,7 +324,13 @@ private static function shouldIncludeNode(ExecutionContext $exeContext, $directi
324324 */
325325 private static function doesFragmentConditionMatch (ExecutionContext $ exeContext ,/* FragmentDefinition | InlineFragment*/ $ fragment , ObjectType $ type )
326326 {
327- $ conditionalType = Utils \TypeInfo::typeFromAST ($ exeContext ->schema , $ fragment ->typeCondition );
327+ $ typeConditionAST = $ fragment ->typeCondition ;
328+
329+ if (!$ typeConditionAST ) {
330+ return true ;
331+ }
332+
333+ $ conditionalType = Utils \TypeInfo::typeFromAST ($ exeContext ->schema , $ typeConditionAST );
328334 if ($ conditionalType === $ type ) {
329335 return true ;
330336 }
@@ -394,22 +400,9 @@ private static function resolveField(ExecutionContext $exeContext, ObjectType $p
394400 'variableValues ' => $ exeContext ->variableValues ,
395401 ]);
396402
397- // If an error occurs while calling the field `resolve` function, ensure that
398- // it is wrapped as a GraphQLError with locations. Log this error and return
399- // null if allowed, otherwise throw the error so the parent field can handle
400- // it.
401- try {
402- $ result = call_user_func ($ resolveFn , $ source , $ args , $ info );
403- } catch (\Exception $ error ) {
404- $ reportedError = Error::createLocatedError ($ error , $ fieldASTs );
405-
406- if ($ returnType instanceof NonNull) {
407- throw $ reportedError ;
408- }
409-
410- $ exeContext ->addError ($ reportedError );
411- return null ;
412- }
403+ // Get the resolve function, regardless of if its result is normal
404+ // or abrupt (error).
405+ $ result = self ::resolveOrError ($ resolveFn , $ source , $ args , $ info );
413406
414407 return self ::completeValueCatchingError (
415408 $ exeContext ,
@@ -420,6 +413,16 @@ private static function resolveField(ExecutionContext $exeContext, ObjectType $p
420413 );
421414 }
422415
416+ // Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField`
417+ // function. Returns the result of resolveFn or the abrupt-return Error object.
418+ private static function resolveOrError ($ resolveFn , $ source , $ args , $ info )
419+ {
420+ try {
421+ return call_user_func ($ resolveFn , $ source , $ args , $ info );
422+ } catch (\Exception $ error ) {
423+ return $ error ;
424+ }
425+ }
423426
424427 public static function completeValueCatchingError (
425428 ExecutionContext $ exeContext ,
@@ -440,6 +443,8 @@ public static function completeValueCatchingError(
440443 try {
441444 return self ::completeValue ($ exeContext , $ returnType , $ fieldASTs , $ info , $ result );
442445 } catch (Error $ err ) {
446+ // If `completeValue` returned abruptly (threw an error), log the error
447+ // and return null.
443448 $ exeContext ->addError ($ err );
444449 return null ;
445450 }
@@ -465,6 +470,10 @@ public static function completeValueCatchingError(
465470 */
466471 private static function completeValue (ExecutionContext $ exeContext , Type $ returnType ,/* Array<Field> */ $ fieldASTs , ResolveInfo $ info , &$ result )
467472 {
473+ if ($ result instanceof \Exception) {
474+ throw Error::createLocatedError ($ result , $ fieldASTs );
475+ }
476+
468477 // If field type is NonNull, complete for inner type, and throw field error
469478 // if result is null.
470479 if ($ returnType instanceof NonNull) {
@@ -514,29 +523,29 @@ private static function completeValue(ExecutionContext $exeContext, Type $return
514523
515524 // Field type must be Object, Interface or Union and expect sub-selections.
516525 if ($ returnType instanceof ObjectType) {
517- $ objectType = $ returnType ;
526+ $ runtimeType = $ returnType ;
518527 } else if ($ returnType instanceof AbstractType) {
519- $ objectType = $ returnType ->getObjectType ($ result , $ info );
528+ $ runtimeType = $ returnType ->getObjectType ($ result , $ info );
520529
521- if ($ objectType && !$ returnType ->isPossibleType ($ objectType )) {
530+ if ($ runtimeType && !$ returnType ->isPossibleType ($ runtimeType )) {
522531 throw new Error (
523- "Runtime Object type \"$ objectType \" is not a possible type for \"$ returnType \". "
532+ "Runtime Object type \"$ runtimeType \" is not a possible type for \"$ returnType \". "
524533 );
525534 }
526535 } else {
527- $ objectType = null ;
536+ $ runtimeType = null ;
528537 }
529538
530- if (!$ objectType ) {
539+ if (!$ runtimeType ) {
531540 return null ;
532541 }
533542
534543 // If there is an isTypeOf predicate function, call it with the
535544 // current result. If isTypeOf returns false, then raise an error rather
536545 // than continuing execution.
537- if (false === $ objectType ->isTypeOf ($ result , $ info )) {
546+ if (false === $ runtimeType ->isTypeOf ($ result , $ info )) {
538547 throw new Error (
539- "Expected value of type $ objectType but got: $ result. " ,
548+ "Expected value of type $ runtimeType but got: $ result. " ,
540549 $ fieldASTs
541550 );
542551 }
@@ -549,15 +558,15 @@ private static function completeValue(ExecutionContext $exeContext, Type $return
549558 if ($ selectionSet ) {
550559 $ subFieldASTs = self ::collectFields (
551560 $ exeContext ,
552- $ objectType ,
561+ $ runtimeType ,
553562 $ selectionSet ,
554563 $ subFieldASTs ,
555564 $ visitedFragmentNames
556565 );
557566 }
558567 }
559568
560- return self ::executeFields ($ exeContext , $ objectType , $ result , $ subFieldASTs );
569+ return self ::executeFields ($ exeContext , $ runtimeType , $ result , $ subFieldASTs );
561570 }
562571
563572
0 commit comments