fn validate_type_implements_interface()

in compiler/crates/schema-validate/src/lib.rs [329:430]


    fn validate_type_implements_interface<T: TypeWithFields + Named>(
        &self,
        type_: &T,
        interface: &Interface,
    ) {
        let object_field_map = self.field_map(type_.fields());
        let interface_field_map = self.field_map(&interface.fields);
        let context = ValidationContextType::TypeNode(type_.name());

        // Assert each interface field is implemented.
        for (field_name, interface_field) in interface_field_map {
            // Assert interface field exists on object.
            if !object_field_map.contains_key(&field_name) {
                self.report_error(
                    SchemaValidationError::InterfaceFieldNotProvided(
                        interface.name,
                        field_name,
                        type_.name(),
                    ),
                    context,
                );
                continue;
            }

            let object_field = object_field_map.get(&field_name).unwrap();
            // Assert interface field type is satisfied by object field type, by being
            // a valid subtype. (covariant)
            if !self
                .schema
                .is_type_subtype_of(&object_field.type_, &interface_field.type_)
            {
                self.report_error(
                    SchemaValidationError::NotASubType(
                        interface.name,
                        field_name,
                        self.schema.get_type_name(interface_field.type_.inner()),
                        type_.name(),
                        self.schema.get_type_name(object_field.type_.inner()),
                    ),
                    context,
                );
            }

            // Assert each interface field arg is implemented.
            for interface_argument in interface_field.arguments.iter() {
                let object_argument = object_field
                    .arguments
                    .iter()
                    .find(|arg| arg.name == interface_argument.name);

                // Assert interface field arg exists on object field.
                if object_argument.is_none() {
                    self.report_error(
                        SchemaValidationError::InterfaceFieldArgumentNotProvided(
                            interface.name,
                            field_name,
                            interface_argument.name,
                            type_.name(),
                        ),
                        context,
                    );
                    continue;
                }
                let object_argument = object_argument.unwrap();

                // Assert interface field arg type matches object field arg type.
                // (invariant)
                // TODO: change to contravariant?
                if interface_argument.type_ != object_argument.type_ {
                    self.report_error(
                        SchemaValidationError::NotEqualType(
                            interface.name,
                            field_name,
                            interface_argument.name,
                            self.schema.get_type_name(interface_argument.type_.inner()),
                            type_.name(),
                            self.schema.get_type_name(object_argument.type_.inner()),
                        ),
                        context,
                    );
                }
                // TODO: validate default values?
            }

            // Assert additional arguments must not be required.
            for object_argument in object_field.arguments.iter() {
                if !interface_field.arguments.contains(object_argument.name)
                    && object_argument.type_.is_non_null()
                {
                    self.report_error(
                        SchemaValidationError::MissingRequiredArgument(
                            type_.name(),
                            field_name,
                            object_argument.name,
                            interface.name,
                        ),
                        context,
                    );
                }
            }
        }
    }