Perhaps a compiler issue?

Description

It appears that we very occasionally get generated javascript that is invalid. Invalid here means it will compile and run, but during runtime it will throw an error because of missing variable names / null or undefined.

It's really hard / impossible to reliably recreate, and as mentioned only seems to happen once out of every few hundred builds.

The code in question:

(Yes, this is terrible code but it works 99% of the time.)

The erring output looks like this:

A recompile fixes the output and spits out this:

The issue from the first compilation results in a runtime error of "priorities__$1 is not defined"

We are using

Environment

Sorry, but we're not sure. We use CircleCI which is likely a linux flavor.

shadow-cljs is our build tool at 2.4.10.

Activity

Show:
Mike Fikes
September 27, 2018, 3:11 AM

Does your project have some other namespace that starts off with priorities.? (Such as priorities.core.)
Are you using the arallel-build compiler option set to true?

import
September 27, 2018, 3:30 PM

Comment made by: lwhorton

Yes to both counts:
```
src/priorities/views.cljs
1ns priorities.views

src/priorities/goals.cljs
1ns priorities.goals

src/priorities/specs.cljs
1ns priorities.specs

src/priorities/events.cljs
1ns priorities.events

src/priorities/core.cljs
1ns priorities.core
```

https://shadow-cljs.github.io/docs/UsersGuide.html#compiler-options (parallel builds is always enabled).

import
September 27, 2018, 5:32 PM

Comment made by: lwhorton

After closer inspection I'm fairly confident the above code working/not-working are at least pointing to the same compiled fn. We use keywords "goals" and "order", which are allocated in the working file as:
```
FA = new C(null, "goals", "goals", -1712076283),
zH = new C(null, "order", "order", -1254677256),
```
and we can see that the output code makes use of both `zH` and `FA`.

David Nolen
September 27, 2018, 5:44 PM

This is just not minimal enough to consider

Thomas Heller
October 15, 2018, 9:40 PM

FWIW this is an actual CLJS compiler race condition.

cljs.compiler/munge decides to munge a variable if a namespace "root" starts with that variable name but it decides that based on the currently known namespaces. Due to parallel compilation a namespace might be added while still emitting one form so at the beginning it would not munge but then later on it would. This is extremely difficult to reproduce reliable due to the time window where this may happen.

Resulting code somewhat looks like

This was sort of fixed accidentally recently [1]. Since the memoize ensures that at least the same munge/unmunged name is used throughout the file. Not sure anything needs to be done but the strategy for choosing which namespaces to munge seems rather brittle considering this.

[1] https://github.com/clojure/clojurescript/commit/284872fb50cac0bd3a5d13c8e3aeaecd3481e03f#diff-55b85385d2d0bfb6dc20d59ed982d5c8R1477

Assignee

Unassigned

Reporter

import

Labels

Approval

None

Patch

None

Affects versions

Priority

Minor
Configure