Compiler ยท Feb 4, 2020

Announcing BuckleScript 7.1.0

Hongbo Zhang
Compiler Team

About this Release

bs-platform@7.1.0 is a major release. You can try it with npm i -g bs-platform! (If you have permission issues, try sudo npm i --unsafe-perm -g bs-platform)

It was called 7.0.2 but bumped into 7.1.0 due to a soundness fix (a breaking change) as follows:

Previously, the empty array [||] was polymorphic. This happens to be true, since in native an array is not resizable, so users cannot do anything with it. But in JS, we introduced a binding for push which can change the size of an array dynamically. In this case, an empty array cannot be polymorphic any more.

Removing push is possible, but it makes arrays in JS context less useful. To fix this issue while keeping push, we make [||] weakly typed so that its type inference is deferred until the first time it is used. If it is never used across the module, it has to be annotated with a concrete type; otherwise, the type checker will complain.

Several highlighted features are listed as follows:

Raw JavaScript Parsing/Checking

BuckleScript allows users to embed raw JavaScript code as an escape hatch; it used to treat such piece of code as a black box.

In this release we vendor a JavaScript parser (thanks to flowtype) for syntax checking and simple semantics analysis over raw. This is on-going work, but it is already useful now.

First, we now report syntax errors properly for raw.

Second, for simple semantics analysis, we can tell whether the code inside raw is a function or not and the arity of raw function:

ML
let f = [%raw "function(x){return x}"]
RE
let f = [%raw "function(x){return x}"];

Now we know f is a function declaration with no side effect; it can be removed by the dead code analyzer if not used. We also know its arity so that when it's called we know whether it's fully applied or not.

Because this sort of information can be derived from raw directly, the special raw form we introduced as follows is no longer needed:

ML
let f = fun%raw x -> {|x|}
RE
let f = [%raw x => {|x|}];

To reduce interop API surface, this feature will now be discouraged.

We're also exploring using such knowledge on JS literals and regexes checking.

Unboxed Types

One major feature introduced in this release is unboxed types which is blogged here.

Uniform Warning System

Previously warnings are reported in two ways:

  • The OCaml compiler style: -w +10

  • Ad-hoc warnings introduced by flags -bs-warn-unimplemented-external

In this release, we make such integration so that BuckleScript warnings are handled in the same way as OCaml's own warnings, for example, the warning attribute below can also turn off BuckleScript warnings now.

RE
[@warning "-101"]; // file-level config

Based on this effort, we have changed all BuckleScript warnings into OCaml style warnings to reduce user-level complexity.

The newly introduced warnings are listed via bsc -warn-help:

101 BuckleScript warning: Unused bs attributes 102 BuckleScript warning: polymorphic comparison introduced (maybe unsafe) 103 BuckleScript warning: about fragile FFI definitions 104 BuckleScript warning: bs.deriving warning with customized message 105 BuckleScript warning: the external name is inferred from val name is unsafe from refactoring when changing value name 106 BuckleScript warning: Unimplemented primitive used: 107 BuckleScript warning: Integer literal exceeds the range of representable integers of type int 108 BuckleScript warning: Uninterpreted delimiters (for unicode)

We also recommend users to turn on warnerror and only disable warnings for some specific files.

We've also upgraded the Reason parser refmt to 3.6.0.

A full list of changes is available here: https://github.com/BuckleScript/bucklescript/blob/master/Changes.md#702

This article was originally released on https://bucklescript.github.io/blog/2020/02/04/release-7-1-0
Want to read more?
Back to Overview