Repository: shader-slang/slang
File: source/slang/slang-check-conversion.cpp (C++)

Code before:
    UInt& ioInitArgIndex)
{
    // First, we will check if we have run out of arguments
    // on the initializer list.
    //
    UInt initArgCount = fromInitializerListExpr->args.getCount();
    if (ioInitArgIndex >= initArgCount)
    {
        // If we are at the end of the initializer list,
        // then our ability to read an argument depends
        // on whether the type we are trying to read
        // is default-initializable.
        //
        // For resource types, this is definitely not true.
        // Resource types can only ever be bound to parameters.
        // But there is likely a fair amount of legacy code
        // out there that depends on it being true. This should
        // eventually be an error, but for now it's a warning.
        // Use diagnoseOnce to avoid duplicate warnings when iterating
        // over array elements or struct fields.
        if (as<ResourceType>(toType))
        {
            diagnoseOnce(
                fromInitializerListExpr->loc,
                Diagnostics::cannotDefaultInitializeResourceType,
                toType);
        }

        // For now, we will just pretend like everything
        // is default-initializable and move along.
        return true;
    }

    // Okay, we have at least one initializer list expression,
    // so we will look at the next expression and decide
    // whether to use it to initialize the desired type
    // directly (possibly via casts), or as the first sub-expression
    // for aggregate initialization.
    //
    auto firstInitExpr = fromInitializerListExpr->args[ioInitArgIndex];
    if (shouldUseInitializerDirectly(toType, firstInitExpr))
    {
        ioInitArgIndex++;
        return _coerce(
            CoercionSite::Initializer,
            toType,
            outToExpr,
            firstInitExpr->type,
            firstInitExpr,
            getSink(),
            nullptr);

Review comment (suggestion):
New problem. If we put the check in here, then it'll get triggered by something as innocuous as:
```slang
struct Test1 {
  float value;
  Texture2D<float4> tex[2];
};
ParameterBlock<Test1> test1;
```
That's because we create a default constructor while checking the struct, and when we attempt to build one for the array it uses the coerce initializer list path. Hm

Code after:
    UInt& ioInitArgIndex)
{
    // First, we will check if we have run out of arguments
    // on the initializer list.
    //
    UInt initArgCount = fromInitializerListExpr->args.getCount();
    if (ioInitArgIndex >= initArgCount)
    {
        // If we are at the end of the initializer list,
        // then our ability to read an argument depends
        // on whether the type we are trying to read
        // is default-initializable.
        //
        // For now, we will just pretend like everything
        // is default-initializable and move along.
        return true;
    }

    // Okay, we have at least one initializer list expression,
    // so we will look at the next expression and decide
    // whether to use it to initialize the desired type
    // directly (possibly via casts), or as the first sub-expression
    // for aggregate initialization.
    //
    auto firstInitExpr = fromInitializerListExpr->args[ioInitArgIndex];
    if (shouldUseInitializerDirectly(toType, firstInitExpr))
    {
        ioInitArgIndex++;
        return _coerce(
            CoercionSite::Initializer,
            toType,
            outToExpr,
            firstInitExpr->type,
            firstInitExpr,
            getSink(),
            nullptr);
    }

    // If there is somehow an error in one of the initialization
    // expressions, then everything could be thrown off and we
    // shouldn't keep trying to read arguments.
    //
    if (IsErrorExpr(firstInitExpr))
    {
        // Stop reading arguments, as if we'd reached
        // the end of the list.
        //
        ioInitArgIndex = initArgCount;
        return true;
    }