in src/Validation.cpp [1265:1422]
bool ValidateExecutableVisitor::validateVariableType(bool isNonNull,
const ValidateType& variableType, const schema_location& position,
const ValidateType& inputType)
{
if (!variableType)
{
_errors.push_back({ "Unknown variable type", position });
return false;
}
const auto variableKind = variableType->get().kind();
if (variableKind == introspection::TypeKind::NON_NULL)
{
const auto ofType = getValidateType(variableType->get().ofType().lock());
if (!ofType)
{
_errors.push_back({ "Unknown Non-Null variable type", position });
return false;
}
return validateVariableType(true, ofType, position, inputType);
}
if (!inputType)
{
_errors.push_back({ "Unknown input type", position });
return false;
}
const auto inputKind = inputType->get().kind();
switch (inputKind)
{
case introspection::TypeKind::NON_NULL:
{
if (!isNonNull)
{
// https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed
_errors.push_back({ "Expected Non-Null variable type", position });
return false;
}
// Unwrap and check the next one.
const auto ofType = getValidateType(inputType->get().ofType().lock());
if (!ofType)
{
_errors.push_back({ "Unknown Non-Null input type", position });
return false;
}
return validateVariableType(false, variableType, position, ofType);
}
case introspection::TypeKind::LIST:
{
if (variableKind != inputKind)
{
// https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed
_errors.push_back({ "Expected List variable type", position });
return false;
}
// Unwrap and check the next one.
const auto variableOfType = getValidateType(variableType->get().ofType().lock());
if (!variableOfType)
{
_errors.push_back({ "Unknown List variable type", position });
return false;
}
const auto inputOfType = getValidateType(inputType->get().ofType().lock());
if (!inputOfType)
{
_errors.push_back({ "Unknown List input type", position });
return false;
}
return validateVariableType(false, variableOfType, position, inputOfType);
}
case introspection::TypeKind::INPUT_OBJECT:
{
if (variableKind != inputKind)
{
// https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed
_errors.push_back({ "Expected Input Object variable type", position });
return false;
}
break;
}
case introspection::TypeKind::ENUM:
{
if (variableKind != inputKind)
{
// https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed
_errors.push_back({ "Expected Enum variable type", position });
return false;
}
break;
}
case introspection::TypeKind::SCALAR:
{
if (variableKind != inputKind)
{
// https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed
_errors.push_back({ "Expected Scalar variable type", position });
return false;
}
break;
}
default:
{
// https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed
_errors.push_back({ "Unexpected input type", position });
return false;
}
}
const auto variableName = variableType->get().name();
if (variableName.empty())
{
_errors.push_back({ "Unknown variable type", position });
return false;
}
const auto inputName = inputType->get().name();
if (inputName.empty())
{
_errors.push_back({ "Unknown input type", position });
return false;
}
if (variableName != inputName)
{
// https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed
std::ostringstream message;
message << "Incompatible variable type: " << variableName << " name: " << inputName;
_errors.push_back({ message.str(), position });
return false;
}
return true;
}