purescript-backend-optimizer icon indicating copy to clipboard operation
purescript-backend-optimizer copied to clipboard

Name clash between module and constructor name

Open kamenchunathan opened this issue 1 year ago • 1 comments

When a data constructor has the same name as an imported module, in the generated javascript they also have the same name resulting in an error when run

Here is a minimal example

Bar.purs

module Bar where

import Prelude

-- This function does not do anything it only needs to be significantly complicated
-- so that it won't be inlined and instead the module it is in imported
placeHolder :: Int -> String
placeHolder i | mod 2 i == 0 = "2"
placeHolder i | mod 3 i == 0 = "2"
placeHolder i | mod 5 i == 0 = "2"
placeHolder i | mod 7 i == 0 = "2"
placeHolder _ = "yipee"

Main.purs

module Main where

import Prelude

import Bar (placeHolder)
import Effect (Effect)
import Effect.Console (log)

data FooBar = Foo  | Bar

main :: Effect Unit
main = do
  -- use placeholder to ensure it is actually in the generated javascript
  log $ placeHolder 3

Here Bar is the name of a data constructor for the `FooBar' type and the name of a module The generated javascript using purescript-backend-optimizer is:

import * as Bar from "../Bar/index.js";
import * as Effect$dConsole from "../Effect.Console/index.js";
const $FooBar = tag => tag;
const Foo = /* #__PURE__ */ $FooBar("Foo");
const Bar = /* #__PURE__ */ $FooBar("Bar");
const main = /* #__PURE__ */ Effect$dConsole.log(/* #__PURE__ */ Bar.placeHolder(3));
export {$FooBar, Bar, Foo, main};

Running this gives an error

✘ [ERROR] The symbol "Bar" has already been declared

    output-es/Main/index.js:5:6:
      5 │ const Bar = /* #__PURE__ */ $FooBar("Bar");
        ╵       ~~~

  The symbol "Bar" was originally declared here:

    output-es/Main/index.js:1:12:
      1 │ import * as Bar from "../Bar/index.js";
        ╵             ~~~

The default purescript backend renames the imported module to "Bar_1" when generating the javascript removing the name clash and this seems like the easiest way to fix this issue. Javascript generated by default backend

import * as Bar_1 from "../Bar/index.js";
import * as Effect_Console from "../Effect.Console/index.js";
var Foo = /* #__PURE__ */ (function () {
    function Foo() {

    };
    Foo.value = new Foo();
    return Foo;
})();
var Bar = /* #__PURE__ */ (function () {
    function Bar() {

    };
    Bar.value = new Bar();
    return Bar;
})();
var main = /* #__PURE__ */ Effect_Console.log(/* #__PURE__ */ Bar_1.placeHolder(3));
export {
    Foo,
    Bar,
    main
};

purs-backend-es v1.4.2 used

kamenchunathan avatar Mar 22 '24 11:03 kamenchunathan

Thanks! This is an easy bit of hygiene to forget.

natefaubion avatar Mar 22 '24 22:03 natefaubion