Skip to content

Incorrect JS outputs when pattern matching with empty list #7235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
3 of 5 tasks
dsiu opened this issue Jan 9, 2025 · 1 comment · Fixed by #7237
Closed
3 of 5 tasks

Incorrect JS outputs when pattern matching with empty list #7235

dsiu opened this issue Jan 9, 2025 · 1 comment · Fixed by #7237

Comments

@dsiu
Copy link

dsiu commented Jan 9, 2025

Starting from alpha.5 (up to the current alpha.7), the following code generates incorrect js output:

let isEmpty: 'a. list<'a> => bool = x =>
  switch x {
  | list{} => true
  | _ => false
  }

let isNotEmpty: 'a. list<'a> => bool = xs => !isEmpty(xs)

Incorrect JS output (Playground):

// Generated by ReScript, PLEASE EDIT WITH CARE

function isEmpty(x) {
  return !x;
}

function isNotEmpty(xs) {
  return xs;
}

export {
  isEmpty,
  isNotEmpty,
}
/* No side effect */

Whereas alphe.4 and before generates correctly (Playground):

// Generated by ReScript, PLEASE EDIT WITH CARE


function isEmpty(x) {
  if (x) {
    return false;
  } else {
    return true;
  }
}

function isNotEmpty(xs) {
  return !(
    xs ? false : true
  );
}

export {
  isEmpty,
  isNotEmpty,
}
/* No side effect */

I found out this problem when porting [Relude](https://github.com/dsiu/rescript-relude) to rescript@v12. The following Jest tests fails:

 test("isNotEmpty is false for empty list", () => expect(List.isNotEmpty(list{}))->toBe(false))

 test("isNotEmpty is true for non-empty list", () => expect(List.isNotEmpty(list{1}))->toBe(true))
Summary of all failing tests
 FAIL  __tests__/Relude_List_test.bs.js
  ● List › isNotEmpty is false for empty list

    expect(received).toBe(expected) // Object.is equality

    Expected: false
    Received: 0

      at affirm (node_modules/@glennsl/rescript-jest/src/jest.bs.js:73:36)
      at Object.<anonymous> (node_modules/@glennsl/rescript-jest/src/jest.bs.js:220:5)

  ● List › isNotEmpty is true for non-empty list

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: {"hd": 1, "tl": 0}

      at affirm (node_modules/@glennsl/rescript-jest/src/jest.bs.js:73:36)
      at Object.<anonymous> (node_modules/@glennsl/rescript-jest/src/jest.bs.js:220:5)

Thank you for filing! Check list:

  • Is it a bug? Usage questions should often be asked in the forum instead.
  • Concise, focused, friendly issue title & description.
  • A minimal, reproducible example.
  • OS and browser versions, if relevant.
  • Is it already fixed in master? Instructions
@dsiu dsiu changed the title Incorrect JS output pattern matching with empty list Incorrect JS outputs when pattern matching with empty list Jan 9, 2025
cristianoc added a commit that referenced this issue Jan 9, 2025
…ean optimisations.

The pattern matching case  for empty list `switch x { | list{} =>` used to compile to `if(x)`, which interferes with boolean optimisation.
Now it compiles to `if(x ==0)` which is the same output as for `if(x == list{})`.

Fixes #7235
cristianoc added a commit that referenced this issue Jan 9, 2025
…ean optimisations.

The pattern matching case  for empty list `switch x { | list{} =>` used to compile to `if(x)`, which interferes with boolean optimisation.
Now it compiles to `if(x ==0)` which is the same output as for `if(x == list{})`.

Fixes #7235
@cristianoc
Copy link
Collaborator

The previous output if(x) ... was one boolean compiler optimisation away from the problem.
Addressed in #7237

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants