The big migration thread for ReScript v11 (and uncurried mode)

The issue is specific to @as in @obj externals. In uncurried mode, this does not erase the parameter from the function definition leading to weird errors that say more arguments are required than the error specifies (try changing the playground link above to 11.0.0-rc.7).

Perhaps as a symptom of this, in uncurried mode when @as is used with @obj it claims to require all arguments to be specified (which defeats the purpose of optional arguments). Here’s another playground link that better demonstrates this issue.

I assumed @obj was not long for this world as it’s functionality was completely replaced by optional record fields (although as it turns out there is this weird edge case that isn’t covered). Perhaps I should be logging a bug against @obj instead?

Well I have no idea how complex a fix would be, but it might be worth it! @obj is no longer the default technique for object bindings but it does have a few use cases remaining.

1 Like

We have almost finished the migration, it remains a case that I don’t know the fix.
We’re using ppx-lenses, a ppx that produces functions. But I think the ppx doesn’t output uncurried functions so there is a mismatch like this :

Is there a workaround for this case ?

2 Likes

Hi, I just noticed that @ocaml.doc doesn’t work anymore. Is there a way in v11 to write a comment in a .res file and have it show up in the compiled .js file?

I don’t think any of the docs solutions has ever emitted actual JS comments. Today, instead of @ocaml.doc you’d use the dedicated syntax:

/** My function */
let someFun = () => {()}

Although a lot of the doc comments will appear in the emitted TypeScript via gentype, maybe that’s what you’re referring to?

I don’t think there’s any other workaround than migrating the PPX to support uncurried. Most of uncurried is at the syntax level, and the heavy lifting is done in the parser. PPX:es transform the AST after the parser has parsed it, so they need to account for the internal representation of uncurried to work properly.

There are however quite a few PPX:es that has migrated already so there’s plenty of inspirational material to look at someone decides it’s worth taking a stab at it.

A note for people migrating: @unwrapped seems to have issues in v11. The workaround (or rather new preferred solution) is to use an unboxed variant. More details and code examples in this issue: Uncurried external function with @unwrap polymorphic variant argument does not unwrap in output · Issue #5604 · rescript-lang/rescript-compiler · GitHub

1 Like

Did anyone else encounter an issue with recursive module while migrating?
I described the issue which is blocking me from completing the migration here:

1 Like

I think it’s a ligit regression, you’re just the only one who used recursive modules. I guess the team will take a look when they breath out after v11 release.

1 Like

I just started migrating our codebase to v11 by bumping the versions and seeing what breaks, and the first breakage is in rescript-jzon (a heavily used dependency):

  We've found a bug for you!
  <snip>/node_modules/rescript-jzon/src/Jzon.res:84:47-52

  82 ┆ 
  83 ┆ let encode = codec => codec.encode
  84 ┆ let encodeString = (codec, value) => codec->encode(value)->Js.Json.stri
     ┆ ngify
  85 ┆ 
  86 ┆ let decode = codec => codec.decode

  This uncurried function has type t<'a> => encode<'a>
  It is applied with 2 arguments but it requires 1.

Are we supposed to report this as a compatibility issue to the library, or is(/will) there be a way to make compilation use the old (I guess curried?) mode? Or is this a different bug entirely?

You can set uncurried: false in your bsconfig

Ideally the libraries would publish a new major version that is compatible with v11’s new uncurried conventions. At least for this particular library it would be easy to vendor and fix up the Jzon.res and Jzon.resi until the issues have been resolved on upstream.

I encountered a problem with GenType typings for JSON.t and Dict.t.
Here is the issue explaining it with a reproduction repo:

Did anyone encounter something similar? Should I create shim files for them?

Thanks!

1 Like

Just found this comment, does it mean they are not ready yet? If so, sorry for inconvenience.

1 Like

I have an opaque type that I want to create an immutable set for. In order to do that in a type safe manner I’ve defined a module type for Belt.Set (since one isn’t provided out-of-the-box). This worked fine in v10 and v11 with uncurrying disabled, but in uncurried mode it breaks with the cryptic error seen below. I understand there’s a curried/uncurried function type mismatch, and I’m guessing the compiler is trying to tell me that I need to make the function type curried somehow, but I have no idea how to specify a curried function of arity 1.

tl;dr: How can I fix the module type so that it matches the actual type of Belt.Set?

Minimal reproducible example:

module type S = {
  type value
  type t

  let fromArray: array<value> => t
}

module Id: {
  type id
  module Set: S with type value = id
} = {
  type id = int
  module Set = Belt.Set.Int
}

yields

[E] Line 11, column 4:
Signature mismatch:
  ...
  In module Set:
  Values do not match:
    let fromArray: array<value> => t (curried)
  is not included in
    let fromArray: array<value> => t (uncurried)
  playground.res:5:3-34: Expected declaration
  playground.res: Actual declaration

Full playground example:

1 Like

An even simpler example demonstrating the same problem, with a different error:

let f: array<int> => Belt.Set.Int.t = Belt.Set.Int.fromArray

yields:

[E] Line 1, column 38:
This function is a curried function where an uncurried function is expected

How do you specify a curried function type of arity 1?

1 Like

You need to wrap it manually with another function and it’ll work: ReScript Playground

This has to do with uncurried mode being able to compile external dependencies as either curried or uncurried, but not internal dependencies (things that ship with the compiler). @cristianoc can probably expand a bit if needed.

2 Likes

Hmm, OK. Probably easier to vendor the whole thing then, since it’s quite a few functions.

Thanks for the quick response!

1 Like

Yeah simply vendoring the module should mean you don’t need to make any changes at all, since it can be compiled in uncurried mode directly if that’s the mode that’s configured in your project. So when it’s possible, vendoring is the way to go.

4 Likes