I upgraded my Play+ScalaJS project from ScalaJS 0.6.32 to 1.4.0 several weeks ago. All has been working fine in development. Today I tried to deploy it and thus executed fullLinkJS
for the first time. It generated a number of errors:
sbt:browser> fullLinkJS
[info] Full optimizing /Users/bwbecker/oat/src/oat3/_browser/target/scala-2.12/browser-opt
[error] c91662c1ae832d6a8493/oat/browser/views/bulkmail/BMailCreateView.scala(125:43:Apply): scala.Dynamic expected but any found for tree of type org.scalajs.ir.Trees$JSSelect
[error] c91662c1ae832d6a8493/oat/browser/views/components/filteredTable/FilteredBMailTable.scala(81:53:Apply): scala.Dynamic expected but any found for tree of type org.scalajs.ir.Trees$JSSelect
[error] c91662c1ae832d6a8493/oat/browser/models/Autocomplete.scala(156:18:Apply): scala.Dynamic expected but any found for tree of type org.scalajs.ir.Trees$JSSelect
[error] c91662c1ae832d6a8493/oat/browser/views/virtualq/QueueAddEditView.scala(90:52:Apply): scala.Dynamic expected but any found for tree of type org.scalajs.ir.Trees$JSSelect
[error] c91662c1ae832d6a8493/oat/browser/views/bulkmail/edit/BMailSendView.scala(273:62:Apply): scala.Dynamic expected but any found for tree of type org.scalajs.ir.Trees$JSSelect
[error] c91662c1ae832d6a8493/oat/browser/views/bulkmail/TemplateListView.scala(42:64:Apply): scala.Dynamic expected but any found for tree of type org.scalajs.ir.Trees$JSSelect
...
I've looked at about a dozen of the referenced lines in the source code. Most of them refer to either a Play route or invoke the url
method. The rest of them involve a call to jQuery.
The project has a cross-platform subproject. That one does the fullLinkJS just fine. There's also a client-specific ScalaJS project. That's where the errors are happening.
I'm using ScalaJS 1.4.0 and Play 2.6.25.
Suggestions on how to procede?
Later, after reading reply from @sjrd
A sample of the offending code:
private val wapp = routes.oat.wapp.controllers.BMailCtrl
...
window.location.href = wapp.edit(emailId).url // this is the line flagged with the error
window
is defined in org.scalajs.dom
as a js.Dynamic
.
routes
is defined in my code as val routes: js.Dynamic = global.jsRoutes
. The js.Dynamic
type annotation is what is inferred by IntelliJ.
Aha! global
is defined in scala.scalajs.js
as extending scala.Dynamic
. But I believe the jsRoutes
should be interpreted as a js.Dynamic
. It's the routes produced by the Play server.
It looks like I need to change how I access those guys. Researching, particularly, Scala.js GlobalScope.
Still Later -- the fix
I'm recording what I did here so I can mark sjrd's answer as "the answer".
As noted, most of my IR validation errors were on lines of the form
window.location.href = wapp.edit(emailId).url
href
has a type of String
and url
is js.Dynamic
but produces a string. I think therein lies the problem.
The fix, however, was simple: add toString
:
window.location.href = wapp.edit(emailId).url.toString
All the other IR validation errors were variants of this with a similar fix.
The errors you see are "IR checking errors". They mean that there are inconsistencies in the
.sjsir
files that are produced by the compiler. By default, they are only checked forfullOpt
tasks, which is why you have not seen them before. However, that does not mean the IR is any more valid forfastOpt
(it's the same IR!), so the error was always there (latent), but only surfaces now. Having IR checking errors means that the optimizer, or simply the JavaScript code generator, can produce nonsensical results.(IR checking errors are also similar to
VerifyError
s on the JVM.Broadly speaking, there are 3 sources of IR checking errors:
What you are experiencing is the latter issue. It is quite rare. Basically, it happens if you assign (through
=
or passing a function argument, etc.) a value of typejs.Dynamic
to a value of typescala.Dynamic
. For example:The type checker accepts that snippet because, at compile-time,
js.Dynamic
extendsscala.Dynamic
. This is necessary forjs.Dynamic
to expose its dynamism in the first place, so we cannot change that. However, at link- and run-time,js.Dynamic
is a JavaScript type (because it extendsjs.Any
) andscala.Dynamic
is a Scala type, and JavaScript types are never subtypes of Scala types.So where does that leave you?
Look at the code pointed by the error messages. You will need to identify a place where a
js.Dynamic
(or any other JS type that extendsscala.Dynamic
, butjs.Dynamic
is typically the only one like that) is assigned to ascala.Dynamic
.It is extremely rare to write
scala.Dynamic
(or justDynamic
) as a type by hand (and doing so is probably always a mistake), but it could be the case that it is inferred by the compiler, for example if you have two branches of an if/else that return two different subtypes ofscala.Dynamic
.This is all I can say without seeing the problematic code snippet.