// Gets if the type can be constructed from the given list of expressions
        public static bool CanConstructType(ShaderType type, List <ExprResult> args, out string error)
        {
            error = null;

            if (type == ShaderType.Void)
            {
                error = "Cannot construct the 'void' type.";
                return(false);
            }
            if (type.IsHandleType())
            {
                error = $"Cannot manually construct a handle type ('{type}').";
                return(false);
            }

            // Immediately fail if any arguments are arrays or handle types
            var badarg = args.FindIndex(arg => arg.IsArray || arg.Type.IsHandleType());

            if (badarg != -1)
            {
                error = $"Type construction argument {badarg} cannot be an array or handle type ({args[badarg].Type}[{args[badarg].IsArray}].";
                return(false);
            }

            if (!type.IsMatrixType())             // Vectors and scalars
            {
                var ccount = type.GetComponentCount();
                if (ccount == 1)                 // Scalars
                {
                    if (args.Count != 1)
                    {
                        error = "Scalar constructors can only have one argument.";
                        return(false);
                    }
                    if (!args[0].Type.IsScalarType())
                    {
                        error = "Scalars can only be constructed from other non-array scalar types.";
                        return(false);
                    }
                    return(true);
                }
                else                 // Vectors
                {
                    var comptype = type.GetComponentType();
                    if (args.Count > ccount)                     // Too many arguments
                    {
                        error = $"Too many arguments for constructing vector type '{type}'.";
                        return(false);
                    }
                    if (args.Count == 1)                     // Direct casting between vectors -or- filling out entire vector with one value
                    {
                        if (args[0].Type.IsScalarType())
                        {
                            if (!args[0].Type.CanPromoteTo(comptype))
                            {
                                error = $"Cannot construct vector type '{type}' from scalar type '{args[0].Type}'.";
                                return(false);
                            }
                            return(true);
                        }
                        if (!args[0].Type.IsVectorType() || (args[0].Type.GetComponentCount() < ccount))
                        {
                            error = "Can only cast between vector types of the same size or larger (through concatenation).";
                            return(false);
                        }
                        if (!args[0].Type.CanPromoteTo(type))
                        {
                            error = $"No casting rules exist to cast a '{args[0].Type}' vector to a '{type}' vector.";
                            return(false);
                        }
                        return(true);
                    }
                    if (args.Count == ccount)                     // Directly supplying each component
                    {
                        var bidx = args.FindIndex(arg => !arg.Type.IsScalarType() || !arg.Type.CanPromoteTo(comptype));
                        if (bidx != -1)
                        {
                            error = $"Type constructor argument {bidx} must be a '{comptype}' compatible non-array scalar type.";
                            return(false);
                        }
                        return(true);
                    }
                    else                     // Some mix of other argument types
                    {
                        var bidx = args.FindIndex(arg => arg.Type.IsMatrixType() || !arg.Type.GetComponentType().CanPromoteTo(comptype));
                        if (bidx != -1)
                        {
                            error = $"The type constructor argument {bidx} must be a '{comptype}' compatible non-array scalar or vector type.";
                            return(false);
                        }
                        var csum = args.Sum(arg => arg.Type.GetComponentCount());
                        if (csum != ccount)
                        {
                            error = $"The type constructor arguments must provide the exact numer of components required ({ccount} != {csum}).";
                            return(false);
                        }
                        return(true);
                    }
                }
            }
            else                     // Matrices
            {
                if (args.Count == 1) // Constructing a diagonal matrix, or a direct matrix cast
                {
                    if (args[0].Type.IsMatrixType())
                    {
                        return(true);                        // Direct matrix casts always work
                    }
                    if (!args[0].Type.IsScalarType() || !args[0].Type.CanPromoteTo(ShaderType.Float))
                    {
                        error = $"Diagonal matrices can only be constructed from capatible scalar types.";
                        return(false);
                    }

                    return(true);
                }

                // Simply need enough compatible arguments to fill each matrix component exactly
                var bidx = args.FindIndex(arg => arg.Type.IsMatrixType() || !arg.Type.GetComponentType().CanPromoteTo(ShaderType.Float));
                if (bidx != -1)
                {
                    error = $"The matrix constructor argument {bidx} must be a 'Float' compatible scalar or vector type.";
                    return(false);
                }
                var csum = args.Sum(arg => arg.Type.GetComponentCount());
                var tsum = (type == ShaderType.Mat2) ? 4 : (type == ShaderType.Mat3) ? 9 : 16;
                if (tsum != csum)
                {
                    error = $"Matrix constructors must be given exactly enough arguments to fill their components ({csum} != {tsum}).";
                    return(false);
                }

                return(true);
            }
        }