Skip to content

Bug: Variable name collision when wrapping nested containers (map<String, vector<String>>) #249

@timosachsenberg

Description

@timosachsenberg

Description

When autowrap generates code for a method that takes a nested container like libcpp_map[String, StringList] (where StringList is vector<String>), it generates buggy Cython code that reuses the same variable name for both the outer and inner container.

Reproduction

Given a C++ method like:

USI buildUSI(const std::map<String, std::vector<String>>& identifier_to_msrunpath,
             const String& dataset_id,
             bool include_interpretation);

With pxd declaration:

USI buildUSI(const libcpp_map[String, StringList]& identifier_to_msrunpath,
             const String& dataset_id,
             bool include_interpretation) except + nogil

Generated Code (buggy)

def _buildUSI_1(self, dict identifier_to_msrunpath, dataset_id, bool include_interpretation):
    cdef libcpp_map[_String, StringList] * v0 = new libcpp_map[_String, StringList]()
    for _loop_key, _loop_value in identifier_to_msrunpath.items():
        cdef libcpp_vector[_String] * v0 = new libcpp_vector[_String]()  # BUG: redefines v0!
        cdef bytes item0
        for item0 in _loop_value:
           v0.push_back(_String(<char *>item0))
        deref(v0)[deref(<_String *>(<String>_loop_key).inst.get())] = deref(v0)
    del v0
    # ...

Error

pyopenms/_pyopenms_8.pyx:8924:17: cdef statement not allowed here

Cython doesn't allow cdef statements inside a loop body after non-cdef statements.

Expected Behavior

The inner vector should use a different variable name (e.g., v1 or _inner_v0):

def _buildUSI_1(self, dict identifier_to_msrunpath, dataset_id, bool include_interpretation):
    cdef libcpp_map[_String, StringList] * v0 = new libcpp_map[_String, StringList]()
    cdef libcpp_vector[_String] * v1  # Declare outside loop
    cdef bytes item0
    for _loop_key, _loop_value in identifier_to_msrunpath.items():
        v1 = new libcpp_vector[_String]()  # Use different name, assign inside loop
        for item0 in _loop_value:
           v1.push_back(_String(<char *>item0))
        deref(v0)[deref(<_String *>(<String>_loop_key).inst.get())] = deref(v1)
        del v1
    # ...

Workaround

Currently using # wrap-ignore on the affected methods.

Environment

  • autowrap version: (from pip)
  • Cython version: 3.x
  • Python: 3.10

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions