Skip to content

Fix recursive wildcard and membership import resolution issues#39

Merged
Malcolmnixon merged 3 commits into
mainfrom
fix/recursive-wildcard-import-resolution
Jul 15, 2026
Merged

Fix recursive wildcard and membership import resolution issues#39
Malcolmnixon merged 3 commits into
mainfrom
fix/recursive-wildcard-import-resolution

Conversation

@Malcolmnixon

Copy link
Copy Markdown
Member

This pull request implements full support for recursive wildcard and membership imports in the SysML v2 language model, ensuring that unqualified references resolve correctly according to the KerML/SysML v2 grammar. It introduces new logic to handle both forms of recursive imports, updates the data structures to track recursive and membership import status, and adds comprehensive tests to verify correct behavior and edge cases. The changes also clarify and document the distinction between recursive namespace and membership imports.

Recursive import resolution improvements

  • Added logic in ReferenceResolver.cs to resolve unqualified names via recursive wildcard imports (import X::*::**;), searching all namespaces nested within the target and preferring the shallowest match by namespace depth, not string length. [1] [2]
  • Implemented correct handling of recursive membership imports (import X::Y::**;), ensuring the explicitly imported member (Y) itself is brought into scope by its short name, in addition to all nested members.
  • Introduced helper methods FindRecursiveWildcardMatch and LastSegment in ReferenceResolver.cs to support the new resolution logic.

Data structure and parsing updates

  • Updated SysmlImportNode to track whether an import is recursive (IsRecursive) and whether it is a membership import (IsMembershipImport), with detailed documentation explaining their semantics.
  • Modified AstBuilder.cs to extract and propagate the new isRecursive and IsMembershipImport properties when parsing import statements. [1] [2]

Testing

  • Added new tests in WorkspaceLoaderTests.cs to verify:
    • Recursive wildcard imports reach all nested members at any depth.
    • Ambiguous matches resolve to the shallowest namespace depth.
    • Recursive membership imports bring both the target member and its nested descendants into scope.
    • Non-recursive wildcard imports do not reach into nested namespaces.

These changes ensure that the language's import mechanism now conforms to the full SysML v2 specification, including subtle distinctions between recursive namespace and membership imports.

Malcolm Nixon and others added 3 commits July 14, 2026 18:57
Recursive wildcard imports parsed without error but never actually
resolved names in namespaces nested more than one level under the
imported target, because:

- AstBuilder.VisitImportRule discarded the parsed IsRecursive flag
- SysmlImportNode had no field to carry recursion state
- ReferenceResolver.TryResolve's wildcard-import step only ever
  checked one namespace level deep

This is a legitimate, spec-sanctioned construct present in the OMG
conformance corpus (SimpleTests/ImportTest.sysml), but the corpus
sweep only checks for parse errors, never resolution correctness,
so the gap went uncaught.

Fixes:
- SysmlImportNode: added IsRecursive property
- AstBuilder.VisitImportRule: now passes through the parsed
  recursion flag instead of discarding it
- ReferenceResolver: added FindRecursiveWildcardMatch, which
  searches the symbol table for a same-named member in any
  namespace nested at any depth under the imported target when
  IsRecursive is true, preferring the shallowest match on ambiguity

Added 3 regression tests to WorkspaceLoaderTests covering resolution
via recursive wildcard import, resolution via nested-level names,
and the non-recursive control case (must NOT reach nested members).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A recursive membership import (import X::Y::**;) is a distinct grammar
shape from the recursive namespace-import form (import X::*::**;) fixed
in the previous commit: here Y is the explicit membership-import target
itself, not a containing namespace being wildcard-searched. It must
bring Y into scope by its own short name, in addition to reaching Y's
own nested descendants.

Auditing the codebase for other places sharing this bug class found
that expose's equivalent path (ExposeScopeResolver) already handles
both recursive forms correctly with existing tests (PR #36); this gap
was isolated to plain import statements' ReferenceResolver.

Fixes:
- SysmlImportNode: added IsMembershipImport property, set from
  AstBuilder.VisitImportRule based on which grammar alternative
  (namespaceImport vs membershipImport) was actually parsed
- ReferenceResolver: added a check so a recursive membership import
  also resolves an unqualified reference to the import target itself
  (not just its descendants), guarded so it does not fire for the
  namespace-import recursive form

Added a regression test to WorkspaceLoaderTests covering resolution
of both the membership-import target's own name and its nested
descendants via a single recursive membership import.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Code review of the prior two commits found FindRecursiveWildcardMatch
picked the 'least-nested' match among ambiguous recursive-import
candidates by comparing raw qualified-name string length, not actual
namespace depth. Since segment names vary in length, a deeper match
can have a shorter qualified-name string than a shallower one,
silently violating the documented 'prefer the shallowest match'
invariant.

Fixed to count actual '::'-separated segment depth between the
resolved namespace and the matched name, with a length guard to
avoid an invalid slice range on the exact one-level match (where the
prefix and suffix overlap).

Added a regression test with two same-named members at different
depths, using deliberately long package names at the shallow depth
and short ones at the deep depth, proving the shallower match wins
even though its qualified-name string is longer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant