bool ValidateExecutableVisitor::validateVariableType()

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;
}