Skip to content

Generated JS missing null check when pattern matching JSON.Array and JSON.Object #8251

@jagguji

Description

@jagguji

Bug: Switch pattern matching on JSON.Array and JSON.Object generates incorrect JS when Null case is omitted

When pattern matching on JSON values with both Array and Object cases, the generated JavaScript incorrectly omits the null check, causing runtime failures
when the value is null.

Reproducible Example

This ReScript code generates incorrect JavaScript (missing null check):

  let getSchedule = (dict, key) => {
    dict
    ->Dict.get(key)
    ->Option.mapOr(None, schedule => {
      switch schedule {
      | JSON.Array(array) =>
        Some(
          array->Array.map(finalJson => {
            let finalDict = finalJson->getDictFromJsonObject
            mappingScheduleWithDict(finalDict)
          }),
        )
      | JSON.Object(dict) => Some([mappingScheduleWithDict(dict)])
      | _ => None
      }
    })
  }

Incorrect Output (Bug): this is not handling the null case which should go to the None

  function getSchedule(dict, key) {
    return Stdlib_Option.mapOr(dict[key], undefined, schedule => {
      if (Array.isArray(schedule)) {  // <-- Crashes if schedule is null!
        return schedule.map(finalJson => mappingScheduleWithDict(LogicUtils.getDictFromJsonObject(finalJson)));
      }
      switch (typeof schedule) {
        case "object" :
          return [mappingScheduleWithDict(schedule)];
        default:
          return;
      }
    });
  }

Workaround - Adding explicit Null case generates correct code:

  | Null | _ => None

Correct Output (with Null case):

  if (schedule === null) {
    return;
  }

Additional Evidence - Only Object case generates correct guards:

  switch schedule {
  | JSON.Object(dict) => Some([mappingScheduleWithDict(dict)])
  | _ => None
  }

Correctly generates:

  if (typeof schedule === "object" && schedule !== null && !Array.isArray(schedule))

Expected Behavior

When both Array and Object cases are present without explicit Null, the compiler should still emit the null check before Array.isArray() to prevent runtime
errors, consistent with the single Object case behavior.

Environment

  • ReScript version: 12.0.0
  • OS: macOS / Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions