Skip to main content

MOD015: Imported name collides with a module-level definition

Code: MOD015 Category: Module system Since: the release after v0.51.1 (#1467)

What this error means​

A module imports a name explicitly and defines a module-level binding with the same name. The import can be a selective import (import M (tick)), an aliased symbol (import M (f as tick)), or the selective list of a module alias (import M as L (tick)). The module-level binding can be a func, a let/letrec, or an ADT constructor (an imported constructor colliding with one of the module's own constructors).

A bare tick in that module could mean either binding, so it is rejected — the same rule as Haskell's and Elm's "ambiguous occurrence" and Rust's E0255. Up to v0.51.1 this compiled and the import silently won: the module's own definition was ignored at every bare use, so a program could run the wrong function with no diagnostic.

Example​

module rx/p/q
import rx/p/a (tick) -- binding 1: the import

pure func tick(n: int) -> int = n + 100 -- binding 2: same name

export func main() -> () ! {IO} = println(show(tick(1)))
Error MOD015: 'tick' is both imported (import rx/p/a (tick) at q.ail:2:1) and defined in this
module as a func (at q.ail:4:6) — an imported name and a module-level definition may not share a name.
Fix: rename the local definition, or alias the import: import rx/p/a (tick as aTick)

How to fix​

  • Alias the import so the two bindings have different names: import rx/p/a (tick as aTick) — then tick is yours and aTick is the import.
  • Rename the local definition.
  • With a module alias (import rx/p/a as A (tick)), drop tick from the list and write A.tick — a module alias already gives qualified access to every export.

What is not an error​

  • Lexical binders — a parameter, let, or match binder named like an import shadows it inside its own scope.
  • A module alias alone — import M as L binds no bare names, so a local tick next to it is fine. AILANG has no wildcard (import M) import.
  • Types — a local type T wins over an imported type T; importing type T next to a local constructor T is not a collision either (types and constructors are separate namespaces).
  • The same export imported twice from the same module.