Skip to content

Commit d5e4d3e

Browse files
committed
Address comments.
1 parent 9c1db69 commit d5e4d3e

File tree

2 files changed

+1136
-6
lines changed

2 files changed

+1136
-6
lines changed

_posts/2020-10-27-scalajs-for-scala-3.md

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,26 @@ by: Sébastien Doeraene
55
title: "Implementing Scala.js Support for Scala 3"
66
---
77

8-
Today, the JS platform has become an integral part of the language.
8+
These days, the JS platform has become an integral part of the language.
99
Yet, until last August, support for Scala.js in Scala 3 was close to non-existent.
1010
A first preview was shipped in Dotty 0.27.0-RC1, with support for the portable subset of Scala and native JS types.
1111
Since then, support for non-native JS types was added and will ship as part of Scala 3.0.0-M1.
1212
The only missing feature left is JS exports, which we will implement by the next milestone.
1313

1414
What did it take to add Scala.js support in Scala 3?
15-
How come we managed to do the necessary work in less than 3 months, whereas Scala.js for Scala 2 took 7 years to mature?
15+
How did we manage to do the necessary work in less than 3 months, whereas Scala.js for Scala 2 took 7 years to mature?
1616
Those are questions we aim to explore in this post.
17+
1718
After some background on the architecture of Scala.js for Scala 2, we will cover which components had to be rewritten for Scala 2, and which ones we could reuse.
18-
We will see that only a small fraction required a rewrite.
19+
We will see that only a small fraction of the codebase required a rewrite, namely the compiler plugin (weighing about 11% of the total implementation code of Scala.js).
20+
Other components like the JDK implementation, the linker and optimizer are reused as is.
21+
Last but not least, we could reuse the test suite as well.
22+
23+
This post explores how Scala.js is implemented, and not so much how it is used, although no compiler knowledge is required to enjoy this post.
24+
For readers mostly interested on what Scala 3 has to offer to Scala.js *users*, stay tuned for an upcoming blog post.
1925

2026
## Background: the Scala.js architecture
2127

22-
When we use Scala.js, it can sometimes appear a bit magical.
2328
In a simple sbt project, the only difference between a JVM project and a JS project can be as short as this one-liner:
2429

2530
```scala
@@ -37,6 +42,8 @@ Two settings, and suddenly `run` or `test` will compile the codebase to JavaScri
3742
There are many components that contribute to this behavior.
3843
Just looking at the compilation pipeline, there are already 4 components involved: the compiler plugin for scalac, the linker, and the artifacts for the Scala standard library and the JDK subset that is implemented.
3944

45+
![Scala.js compilation pipeline](/resources/img/blog/scalajs-for-scala-3/compilation-pipeline.svg)
46+
4047
### A compiler plugin
4148

4249
When compiling a Scala.js codebase, the .scala source files are compiled with scalac, augmented with the Scala.js compiler plugin.
@@ -48,7 +55,7 @@ Traits have been lowered to interfaces; lazy vals have been desugared; nested cl
4855
This is how Scala.js is able to keep up-to-date with all the versions of Scala 2, and be available on the same day as new Scala releases.
4956
Not all compile-to-JS languages have that property!
5057

51-
### `.sjsir`files
58+
### `.sjsir` files
5259

5360
.sjsir files are similar to .class files, although they are AST-based (instead of stack-machine-based) and contain features dedicated to JavaScript interoperability.
5461
The .sjsir format and specification is independent of Scala, its compiler or its standard library.
@@ -59,12 +66,44 @@ While we have a proof-of-concept for Java, it is nowhere near usable, however.
5966

6067
.sjsir files have binary compatibility guarantees similar to those of .class files.
6168
With a few exceptions related to JS interop annotations, if changes to a .class files are binary compatible, then the changes applied to the corresponding .sjsir files are also binary compatible.
62-
This allows Scala.js codebase to meaningfully use MiMa to check that they do not break their binary API.
69+
This allows Scala.js codebases to meaningfully use MiMa to check that they do not break their binary API.
6370

6471
The Scala.js linker (optimizer) takes the .sjsir files from the application and from all the transitive dependencies.
6572
In particular, the .sjsir files that are built for the Scala standard library and for the JDK subset.
6673
The linker optimizes all of them together, then emits one .js file for the entire codebase.
6774

75+
### Aside: What about TASTy?
76+
77+
Inevitably, talking about the Scala.js IR raises questions about TASTy.
78+
TASTy has in fact no impact on the implementation of Scala.js for Scala 3; nothing good, nothing bad.
79+
And yet:
80+
81+
* `.sjsir` files are an intermediate typed AST-based language for compiling Scala code.
82+
* `.tasty` files are an intermediate typed AST-based language for compiling Scala code.
83+
84+
When described as above, one may wonder what is the relationship between the Scala.js IR and TASTy.
85+
Could we not just compile from TASTy to JavaScript?
86+
87+
The answer is no, we could not.
88+
TASTy has a very different level of abstraction than the Scala.js IR.
89+
90+
| TASTy | Scala.js IR |
91+
|-------|-------------|
92+
| full Scala type system | erased type system (like the JVM) |
93+
| no interoperability knowledge | specific JS interop features |
94+
| complex Scala features (traits, inner/local classes, lazy vals, etc.) | flat classes and interfaces, no fields in interfaces, simple fields in classes, etc. |
95+
96+
During the compilation pipeline, the compiler first type-checks and elaborates Scala source code into a TASTy-level representation (even in Scala 2, although it is not TASTy itself).
97+
Then, a few dozens of phases successively transform that representation to eliminate Scala features and erase the type system.
98+
It is only at the end of that process that Scala/JVM produces `.class` files while Scala.js procudes `.sjsir` files.
99+
100+
We *can* compile from TASTy to JavaScript, but that does not take away the fact that we have to perform all those phases again.
101+
There is no shortcut.
102+
The best way to do that is to reuse the phases that are already implemented in the compiler, of course.
103+
From there, we still need to compile the lowered representation of the compiler into JavaScript, and the best way to do that is through the Scala.js IR.
104+
105+
Therefore, from the point of view of implementing Scala.js for Scala 3, the presence or absence of TASTy is irrelevant.
106+
68107
### Components of Scala.js core
69108

70109
The components involved here have the following sizes (not counting test files):

0 commit comments

Comments
 (0)