Skip to content

Javascript backend -O1 breaks referential transparency in a function having a Double argument and doing String concatenation

Summary

A pure String value shows up as two different values when output via putStrLn and via console.log.

The following factors seem to concur in triggering this behaviour:

  • The optimization level is -O1 (does not happen with -O0 or -O2)
  • The affected function has a Double argument (does not happen if the argument is Int, see the commented testInt function in the repro case)
  • The String concatenation has certain characteristics (eg. does not happen for the commented testDouble2 function in the repro case and for other similar tweaks to the String concatenation)

Steps to reproduce

See attached repro case Test.hs.

$ for i in $(seq 0 2); do rm -rf Test Test.hi Test.o Test.jsexe; echo compiling with -O$i; javascript-unknown-ghcjs-ghc-9.8.2 -v -O$i -dcore-lint  Test.hs > ghc.log.O$i 2>&1; echo results with -O$i;  ./Test; done
compiling with -O0
results with -O0
1 ab bd
2 ab bd
compiling with -O1
results with -O1
1 ab bd
2 ab
compiling with -O2
results with -O2
1 ab bd
2 ab bd

Loading index.html in a web browser also exhibits the same behaviour in the JS console log.

Expected behavior

The program's output to be identical regardless of the optimization level. The second part of the second line of the -O1 results to be the same as the second part of the first line, i.e. "ab bd" instead of just "ab ".

Environment

  • GHC version used: 9.8.2 JS backend
  • Nodejs version used: v20.11.0
  • Google Chrome version used: 121.0.6167.184 (Official build) (64 bit)

Optional:

  • Operating System:
  • System Architecture:
$ uname -a
Linux abcde 6.7.5-gentoo #1 SMP Mon Feb 19 15:51:31 CET 2024 x86_64 Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz GenuineIntel GNU/Linux
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information