Defining and referencing an enum within a module causes name lookup errors

Hey,

we are just getting started with the mdl sdk and we have some troubles with enums. We’ve created a little repro case that should generate a mdl module that looks somewhat like this:

export enum someEnum
{
    case0 = 0,
    case1 = 1,
    case2 = 2,
    case3 = 3,
    case4 = 4
};

export someEnum foo(someEnum arg0 = case0)
{
    return arg0;
}

However, what we actually get is this:

export enum someEnum [[
]] {
    case0 = 0,
    case1 = 1,
    case2 = 2,
    case3 = 3,
    case4 = 4
};

export ::test::materials::someEnum [[
]] foo(someEnum arg0 = ::test::materials::case0)
[[
]]
{
    return arg0;
}

Note that the return type of the function uses a fully qualified name, as well as the default value for arg0, while the type of arg0 doesn’t.

We did some debugger hackery to get this dump, by forcing it in MDL-SDK\src\io\scene\mdl_elements\mdl_elements_module_builder.cpp:2215 so this is not a final output.

Unfortunately, we can’t generate the module because the module analysis fails because it can’t find the module ::test::materials. Here are the error messages:

C108 ‘test::materials’ is not a package or module name
C108 ‘test::materials’ is not a package or module name
Failed to analyze created module “::test::materials”.

What can we do to fix these errors?

We are using VS 17.1 (and 16.11) with C++20 and we built the mdl sdk from current master (commit d6c9a6560265025a30d16fcd9d664f830ab63109).

Here is the full repro code

#include <mi/mdl_sdk.h>

#include <cassert>
#include <iostream>
#include <string>

using namespace mi::neuraylib;
using mi::base::Handle;

void check(bool test, const IMdl_execution_context* context)
{
    if (!test)
    {
        for (mi::Size i = 0; i < context->get_messages_count(); i++)
            std::cout << context->get_message(i)->get_string() << "\n";
        std::cout.flush();
    }

    assert(test);
}

int main()
{
    // Load the sdk (we use the loader lib that VS generates when building the sdk) 
    Handle neuray { mi_factory<INeuray>(::mi_factory) };
    assert(neuray.is_valid_interface());

    Handle mdlConfig { neuray->get_api_component<IMdl_configuration>() };
    mdlConfig->add_mdl_system_paths();
    mdlConfig->add_mdl_user_paths();

    auto err = neuray->start();
    assert(err == 0);

    Handle factory { neuray->get_api_component<IMdl_factory>() };
    Handle context { factory->create_execution_context() };
    Handle db { neuray->get_api_component<IDatabase>() };
    Handle scope { db->get_global_scope() };
    Handle transaction { scope->create_transaction() };
    Handle expressionFactory { factory->create_expression_factory(transaction.get()) };
    Handle valueFactory { factory->create_value_factory(transaction.get()) };
    Handle typeFactory { factory->create_type_factory(transaction.get()) };
    Handle impExpApi { neuray->get_api_component<IMdl_impexp_api>() };

    err = impExpApi->load_module(transaction.get(), "::df", context.get());
    check(err == 0, context.get());

    // Create module ::test::materials
    Handle moduleBuilder {
        factory->create_module_builder(transaction.get(), "mdl::test::materials", MDL_VERSION_1_0, MDL_VERSION_1_4, context.get())
    };

    // Define enum someEnum
    Handle enumCases { expressionFactory->create_expression_list() };

    for (int i = 0; i < 5; i++)
    {
        auto name = "case" + std::to_string(i);
        Handle value { valueFactory->create_int(i) };
        Handle enumCase { expressionFactory->create_constant(value.get()) };
        enumCases->add_expression(name.data(), enumCase.get());
    }

    err = moduleBuilder->add_enum_type("someEnum", enumCases.get(), nullptr, nullptr, true, context.get());
    check(err == 0, context.get());

    // Get enum type, we have to use the full qualified name, otherwise the handle will be invalid
    Handle enumType { typeFactory->create_enum("::test::materials::someEnum") };
    check(enumType, context.get());

    // Define foo function
    Handle paramTypes { typeFactory->create_type_list() };
    paramTypes->add_type("arg0", enumType.get());

    Handle paramDefaults { expressionFactory->create_expression_list() };
    Handle case0Value { valueFactory->create_enum(enumType.get(), 0) };
    Handle enumDefaultValue { expressionFactory->create_constant(case0Value.get()) };
    paramDefaults->add_expression("arg0", enumDefaultValue.get());

    Handle body { expressionFactory->create_parameter(enumType.get(), 0) };
    check(err == 0, context.get());

    // Add foo to the module, this step fails with the mentioned errors
    err = moduleBuilder->add_function("foo", body.get(), paramTypes.get(), paramDefaults.get(), nullptr, nullptr, nullptr, true,
                                      IType::MK_NONE, context.get());
    check(err == 0, context.get());

    // Write module to disk
    err = impExpApi->export_module(transaction.get(), "mdl::test::materials", "test_material", context.get());
    check(err == 0, context.get());

    err = transaction->commit();
    check(err == 0, context.get());

    err = neuray->shutdown();
    assert(err == 0);
}

I can also share a complete VS 2022 project with our mdl sdk build if you need it. We didn’t make any changes to the sdk itself tho and the code above is the same.

Hi Timo,

what a nice and complete problem description :-)
i will get a dev on it.