@@ -177,7 +177,7 @@ impl SchemaInner {
177
177
let interface = ty. as_interface ( ) . ok_or_else ( || {
178
178
format ! ( "Type \" {}\" is not interface" , interface_name)
179
179
} ) ?;
180
- check_is_valid_implementation ( obj, interface) ?;
180
+ self . check_is_valid_implementation ( obj, interface) ?;
181
181
}
182
182
}
183
183
}
@@ -339,7 +339,7 @@ impl SchemaInner {
339
339
let implemenented_type = ty. as_interface ( ) . ok_or_else ( || {
340
340
format ! ( "Type \" {}\" is not interface" , interface_name)
341
341
} ) ?;
342
- check_is_valid_implementation ( interface, implemenented_type) ?;
342
+ self . check_is_valid_implementation ( interface, implemenented_type) ?;
343
343
}
344
344
}
345
345
}
@@ -373,69 +373,105 @@ impl SchemaInner {
373
373
374
374
Ok ( ( ) )
375
375
}
376
- }
377
376
378
- fn check_is_valid_implementation (
379
- implementing_type : & impl BaseContainer ,
380
- implemented_type : & Interface ,
381
- ) -> Result < ( ) , SchemaError > {
382
- for field in implemented_type. fields . values ( ) {
383
- let impl_field = implementing_type. field ( & field. name ) . ok_or_else ( || {
384
- format ! (
385
- "{} \" {}\" requires field \" {}\" defined by interface \" {}\" " ,
386
- implementing_type. graphql_type( ) ,
387
- implementing_type. name( ) ,
388
- field. name,
389
- implemented_type. name
390
- )
391
- } ) ?;
392
-
393
- for arg in field. arguments . values ( ) {
394
- let impl_arg = match impl_field. argument ( & arg. name ) {
395
- Some ( impl_arg) => impl_arg,
396
- None if !arg. ty . is_nullable ( ) => {
397
- return Err ( format ! (
377
+ fn check_is_child_type ( & self , ty : & TypeRef , child : & TypeRef ) -> bool {
378
+ if child. is_subtype ( ty) {
379
+ return true ;
380
+ }
381
+
382
+ if let Some ( child) = self . types . get ( child. type_name ( ) ) {
383
+ if let Some ( child) = child. as_object ( ) {
384
+ return child. implements . iter ( ) . any ( |i_ty| {
385
+ if let Some ( i_ty) = self . types . get ( i_ty) {
386
+ let type_ref = TypeRef :: named ( i_ty. name ( ) ) ;
387
+
388
+ return self . check_is_child_type ( ty, & type_ref) ;
389
+ }
390
+ false
391
+ } ) ;
392
+ }
393
+
394
+ if let Some ( child) = child. as_interface ( ) {
395
+ return child. implements . iter ( ) . any ( |i_ty| {
396
+ if let Some ( i_ty) = self . types . get ( i_ty) {
397
+ let type_ref = TypeRef :: named ( i_ty. name ( ) ) ;
398
+
399
+ return self . check_is_child_type ( ty, & type_ref) ;
400
+ }
401
+ false
402
+ } ) ;
403
+ }
404
+
405
+ return false ;
406
+ }
407
+
408
+ false
409
+ }
410
+
411
+ fn check_is_valid_implementation (
412
+ & self ,
413
+ implementing_type : & impl BaseContainer ,
414
+ implemented_type : & Interface ,
415
+ ) -> Result < ( ) , SchemaError > {
416
+ for field in implemented_type. fields . values ( ) {
417
+ // Field on the implementing type
418
+ let impl_field = implementing_type. field ( & field. name ) . ok_or_else ( || {
419
+ format ! (
420
+ "{} \" {}\" requires field \" {}\" defined by interface \" {}\" " ,
421
+ implementing_type. graphql_type( ) ,
422
+ implementing_type. name( ) ,
423
+ field. name,
424
+ implemented_type. name
425
+ )
426
+ } ) ?;
427
+
428
+ for arg in field. arguments . values ( ) {
429
+ let impl_arg = match impl_field. argument ( & arg. name ) {
430
+ Some ( impl_arg) => impl_arg,
431
+ None if !arg. ty . is_nullable ( ) => {
432
+ return Err ( format ! (
398
433
"Field \" {}.{}\" requires argument \" {}\" defined by interface \" {}.{}\" " ,
399
434
implementing_type. name( ) ,
400
435
field. name,
401
436
arg. name,
402
437
implemented_type. name,
403
438
field. name,
439
+ )
440
+ . into ( ) ) ;
441
+ }
442
+ None => continue ,
443
+ } ;
444
+
445
+ if !self . check_is_child_type ( & arg. ty , & impl_arg. ty ) {
446
+ return Err ( format ! (
447
10000
+ "Argument \" {}.{}.{}\" is not sub-type of \" {}.{}.{}\" " ,
448
+ implemented_type. name,
449
+ field. name,
450
+ arg. name,
451
+ implementing_type. name( ) ,
452
+ field. name,
453
+ arg. name
404
454
)
405
455
. into ( ) ) ;
406
456
}
407
- None => continue ,
408
- } ;
457
+ }
409
458
410
- if !arg. ty . is_subtype ( & impl_arg. ty ) {
459
+ // field must return a type which is equal to or a sub-type of (covariant) the
460
+ // return type of implementedField field’s return type
461
+ if !self . check_is_child_type ( & field. ty , & impl_field. ty ( ) ) {
411
462
return Err ( format ! (
412
- "Argument \" {}.{}.{}\" is not sub-type of \" {}.{}.{}\" " ,
413
- implemented_type. name,
414
- field. name,
415
- arg. name,
463
+ "Field \" {}.{}\" is not sub-type of \" {}.{}\" " ,
416
464
implementing_type. name( ) ,
417
465
field. name,
418
- arg. name
466
+ implemented_type. name,
467
+ field. name,
419
468
)
420
469
. into ( ) ) ;
421
470
}
422
471
}
423
472
424
- // field must return a type which is equal to or a sub-type of (covariant) the
425
- // return type of implementedField field’s return type
426
- if !impl_field. ty ( ) . is_subtype ( & field. ty ) {
427
- return Err ( format ! (
428
- "Field \" {}.{}\" is not sub-type of \" {}.{}\" " ,
429
- implementing_type. name( ) ,
430
- field. name,
431
- implemented_type. name,
432
- field. name,
433
- )
434
- . into ( ) ) ;
435
- }
473
+ Ok ( ( ) )
436
474
}
437
-
438
- Ok ( ( ) )
439
475
}
440
476
441
477
#[ cfg( test) ]
0 commit comments