rescript-compiler icon indicating copy to clipboard operation
rescript-compiler copied to clipboard

Unnecessary variables generated for record field values

Open cknitt opened this issue 3 years ago • 7 comments

In both ReScript 10.0.0-rc.1 and ReScript 9.1.4,

type options = {
  a: int,
  b: int,
}

@module("some-module")
external func: options => unit = "func"

let test = a => {
  let options = {
    a: a + 1,
    b: 42,
  }

  func(options)
}

compiles to

import * as SomeModule from "some-module";

function test(a) {
  var options_a = a + 1 | 0;
  var options = {
    a: options_a,
    b: 42
  };
  SomeModule.func(options);
}

with an unnecessary variable options_a generated.

In ReScript 10, when making field b optional, an unnecessary variable options_b is generated in addition:

type options = {
  a: int,
  b?: int,
}

@module("some-module")
external func: options => unit = "func"

let test = a => {
  let options = {
    a: a + 1,
    b: 42,
  }

  func(options)
}

compiles to

import * as SomeModule from "some-module";

function test(a) {
  var options_a = a + 1 | 0;
  var options_b = 42;
  var options = {
    a: options_a,
    b: options_b
  };
  SomeModule.func(options);
}

cknitt avatar Aug 19 '22 16:08 cknitt

Not sure what "unnecessary" refers to. Is this implied to be a regression? It seems not.

Not sure why this particular computation, out of all the possible computations, is expected to be inlined.

Is analogous code written directly and not generated through the use of options, inlined?

cristianoc avatar Aug 19 '22 17:08 cristianoc

To clarify:

  1. I would have expected options_a to be inlined. However, this is not a regression, as the behavior is the same in ReScript 9 and 10.
  2. In ReScript 10, I would not have expected inlining behavior to be different depending on whether field b is optional or not.

cknitt avatar Aug 19 '22 17:08 cknitt

Is analogous code written directly and not generated through the use of options, inlined?

Not sure if that's what you mean, but

let test = a => {
  func({
    a: a + 1,
    b: 42,
  })
}

is indeed inlined:

function test(a) {
  SomeModule.func({
        a: a + 1 | 0,
        b: 42
      });
}

In this case, the output is the same irrespective of whether field b is optional or not.

cknitt avatar Aug 19 '22 17:08 cknitt

How do you know that func does not have side effects?

Note that the second example is just sugar for using an option type in the record.

cristianoc avatar Aug 19 '22 17:08 cristianoc

I don't know why it's relevant whether func has side effects.

As for

  1. In ReScript 10, I would not have expected inlining behavior to be different depending on whether field b is optional or not.

it seems that in general optimizations are not applied as soon as a record has at least one optional field, see also #5616.

cknitt avatar Aug 26 '22 11:08 cknitt

You can't inline functions with side effects. And that might lead to generating different code.

cristianoc avatar Aug 26 '22 11:08 cristianoc

It does not mean that the code cannot be simplified, it only suggests a possible reason for why it is how it is.

cristianoc avatar Aug 26 '22 11:08 cristianoc