Fix relative import resolution #402
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR improves name resolution for relative
using/importwith leading dots (.,..,...) and forward references (imports that appear before the target module is defined in the same file tree). It also adds a diagnostic when the number of leading dots exceeds the available module nesting.Today, LanguageServer/StaticLint resolves relative imports only when the target module is already bound, and often treats top-level file scopes as “parents”, which makes sibling imports fragile. Common project layouts (one wrapper file including multiple modules) hit:
using ..Siblingbefore Sibling is defined → unresolved references in the importing moduleimport ..Another(no selectors) → module name “Another” is not bound locally, so qualified calls (Another.f()) don’t resolveThis PR implements:
import Module(no selectors) now binds the module’s identifier in the current scope (matches Julia semantics), so qualified calls likeAnother.f()resolve without needing selectors.RelativeImportTooManyDotswith message: “Relative import has more leading dots than available module nesting.”Implementation details
imports.jl:resolve_import_block: walk leading dots up fromstate.scope; setRelativeImportTooManyDotswhen exceeding the root; when a segment is unresolved (cand === nothing), push the import expr and enclosing module expr intostate.resolveonly; return to retry later.resolve_import: selector-head failure (root2 === nothing) also schedules a retry._mark_import_arg: whenusinged == false(plain import), bind the imported module name intoscope.names;usingkeeps existing behavior (add module toscope.modules).add_to_imported_modules: ensurescope.modulesinitialized when first used.references.jl:resolve_ref_from_module(::Scope): resolve the module’s own name (bindingof(scope.expr)) and exported names viascope_exports.StaticLint.jl:ResolveOnly: callresolve_import(x, state)before resolve_ref/traverse (idempotent; only updates unresolved imports).linting/checks.jl:RelativeImportTooManyDotstoLintCodesand descriptions.Tests
using/import: module C using..SiblingbindsSibling; calls likeSibling.g()resolve even if Sibling is defined later in B.import ..AnothermakesAnothervisible, soAnother.f()resolves.import ....XtriggersRelativeImportTooManyDots.Compatibility and performance