Repository: shader-slang/slang
File: source/slang/slang-ir-lower-optional-type.cpp (C++)

Code before:
            else
                outKind = LoweredOptionalTypeKind::ExistentialValue;
            return true;
        default:
            return false;
        }
    }

    LoweredOptionalTypeInfo* getLoweredOptionalType(IRBuilder*, IRInst* type)
    {
        if (auto loweredInfo = loweredOptionalTypes.tryGetValue(type))
            return loweredInfo->Ptr();
        if (auto loweredInfo = mapLoweredTypeToOptionalTypeInfo.tryGetValue(type))
            return loweredInfo->Ptr();
        if (!type)
            return nullptr;
        if (type->getOp() != kIROp_OptionalType)
            return nullptr;

        RefPtr<LoweredOptionalTypeInfo> info = new LoweredOptionalTypeInfo();
        auto optionalType = cast<IROptionalType>(type);
        auto valueType = optionalType->getValueType();
        while (auto valueOptionalType = as<IROptionalType>(valueType))
        {
            // If the value type is also an Optional, we need to keep lowering it.
            valueType = valueOptionalType->getValueType();
        }

        info->optionalType = (IRType*)type;
        info->valueType = valueType;
        if (typeHasNullValue(valueType, info->kind))
        {
            info->loweredType = valueType;
        }
        else
        {
            info->loweredType = (IRType*)createOptionalStruct(valueType, info);
        }
        mapLoweredTypeToOptionalTypeInfo[info->loweredType] = info;
        loweredOptionalTypes[type] = info;
        return info.Ptr();
    }

    void addToWorkList(IRInst* inst)
    {
        if (workListSet.contains(inst))
            return;

        workList.add(inst);
        workListSet.add(inst);
    }

Review comment (suggestion):
this would mean nested optional<t> is going to introduce additional storage for each level of nesting. Ideally the lowered type for optional<t> should present itself as "typeHasNullValue == true", so we use the lowered type of the inner type exactly as is as the lowered type of the outer type.

Code after:
            else
                outKind = LoweredOptionalTypeKind::ExistentialValue;
            return true;
        default:
            return false;
        }
    }

    LoweredOptionalTypeInfo* getLoweredOptionalType(IRBuilder* builder, IRInst* type)
    {
        if (auto loweredInfo = loweredOptionalTypes.tryGetValue(type))
            return loweredInfo->Ptr();
        if (auto loweredInfo = mapLoweredTypeToOptionalTypeInfo.tryGetValue(type))
            return loweredInfo->Ptr();
        if (!type)
            return nullptr;
        if (type->getOp() != kIROp_OptionalType)
            return nullptr;

        RefPtr<LoweredOptionalTypeInfo> info = new LoweredOptionalTypeInfo();
        auto optionalType = cast<IROptionalType>(type);
        auto valueType = optionalType->getValueType();
        while (auto valueOptionalType = as<IROptionalType>(valueType))
        {
            // If the value type is also an Optional, we need to keep lowering it.
            auto loweredValueOptionalType = getLoweredOptionalType(builder, valueOptionalType);
            valueType = loweredValueOptionalType->loweredType;
        }

        info->optionalType = (IRType*)type;
        info->valueType = valueType;
        if (typeHasNullValue(valueType, info->kind))
        {
            info->loweredType = valueType;
        }
        else
        {
            info->loweredType = (IRType*)createOptionalStruct(valueType, info);
        }
        mapLoweredTypeToOptionalTypeInfo[info->loweredType] = info;
        loweredOptionalTypes[type] = info;
        return info.Ptr();
    }

    void addToWorkList(IRInst* inst)
    {
        if (workListSet.contains(inst))
            return;

        workList.add(inst);
        workListSet.add(inst);