/// <summary>
        /// Gets all constraint types for the given <paramref name="typeParameterSymbol"/>.
        /// </summary>
        /// <param name="typeParameterSymbol">The typeParameterSymbol to act on.</param>
        /// <param name="includeInterfaces">(Optional) True to include, false to exclude the interfaces.</param>
        /// <returns/>
        public static IEnumerable <ITypeSymbol> GetAllConstraintTypes(this ITypeParameterSymbol typeParameterSymbol, bool includeInterfaces = true)
        {
            typeParameterSymbol.ThrowOnNull(nameof(typeParameterSymbol));

            var constraintTypes = includeInterfaces
                                ? GetAllConstraintTypesImplementation(typeParameterSymbol)
                                : GetAllConstraintTypesImplementation(typeParameterSymbol)
                                  .Where(type => type.TypeKind != TypeKind.Interface);

            return(constraintTypes.Distinct());

            //---------------------------------Local Functions--------------------------------------------------------
            IEnumerable <ITypeSymbol> GetAllConstraintTypesImplementation(ITypeParameterSymbol typeParameter, int recursionLevel = 0)
            {
                const int maxRecursionLevel = 40;

                if (recursionLevel > maxRecursionLevel || typeParameter.ConstraintTypes.Length == 0)
                {
                    yield break;
                }

                foreach (ITypeSymbol constraintType in typeParameter.ConstraintTypes)
                {
                    if (constraintType is ITypeParameterSymbol constraintTypeParameter)
                    {
                        var nextOrderTypeParams = GetAllConstraintTypesImplementation(constraintTypeParameter, recursionLevel + 1);

                        foreach (ITypeSymbol type in nextOrderTypeParams)
                        {
                            yield return(type);
                        }
                    }
                    else
                    {
                        yield return(constraintType);
                    }
                }
            }
        }