Constructor is never used to build values. (However, this constructor appears in patterns.)

Hi all!

I have the following code:

module DxfHeader = {
  @deriving(jsConverter)
  type insunits =
    | @as(0) Unspecified
    | @as(1) Inches
    | @as(2) Feet
    | @as(3) Miles
    | @as(4) Millimeters
    | @as(5) Centimeters
    | @as(6) Meters
    | @as(7) Kilometers
    | @as(8) Microinches
    | @as(9) Mils
    | @as(10) Yards
    | @as(11) Angstroms
    | @as(12) Nanometers
    | @as(13) Microns
    | @as(14) Decimeters
    | @as(15) Dekameters
    | @as(16) Hectometers
    | @as(17) Gigameters
    | @as(18) Astronomical
    | @as(19) LightYears
    | @as(20) Parsecs

  type t = {
    // See: https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2016/ENU/AutoCAD-Core/files/GUID-A58A87BB-482B-4042-A00A-EEF55A2B4FD8-htm.html
    @as("$INSUNITS") insunits: option<int>,
  }

  let insunits = ({insunits}) =>
    insunitsFromJs(insunits->Belt.Option.getWithDefault(0))
    ->Belt.Option.getWithDefault(Millimeters)
}

let mmToUnitRatio = (insunits: DxfHeader.insunits) =>
  switch insunits {
  | Unspecified => 1.0
  | Inches => 25.4
  | Feet => 304.8
  | Miles => 1_609_344.0
  | Millimeters => 1.0
  | Centimeters => 10.0
  | Meters => 1000.0
  | Kilometers => 1000_000.0
  | Microinches => 0.0000254
  | Mils => 0.0254
  | Yards => 914.4
  | Angstroms => 1e-7
  | Nanometers => 1e-6
  | Microns => 0.001
  | Decimeters => 100.0
  | Dekameters
  | Hectometers
  | Gigameters
  | Astronomical
  | LightYears
  | Parsecs => 1.0 /* don't care */
  }

type t = {
  header: DxfHeader.t,
  //blocks: Js.Dict.t<DxfBlock.t>,
  //entities: array<DxfEntity.t>,
  //tables: DxfTables.t,
}

type parser
@new @module("./dxf-parser") external newParser: unit => parser = "default"
@bs.send external parseSync: (parser, string) => t = "parseSync"

That is, I have a DXF parser in JS that takes a string and gives a complex object with the shape described with t. One of the things I should use is the dxf.header.$INSUNITS value. It is an enum value from 0 to 20 denoting units of measure. I’d better project them to a variant-type with clear names.

All this compiles and works just fine but the compiler gives me 20 warnings like:

Constructor Decimeters is never used to build values.
(However, this constructor appears in patterns.)

Can’t understand what it tries to tell me. Am I doing something wrong and can shoot my leg?

Interestingly enough, this snipped is extracted out of a bigger context and gives no warnings on the ReScript playground. However, in the real code base where the surrounding code seems nothing to do with the units, the warnings appear.

You’re not necessarily doing anything wrong, but this is a side-effect of working with externals (which are inherently dangerous anyway). The compiler is inferring that the constructors are never used to build values, but it can only see things on the ReScript side. It doesn’t know that the values are built in external JS code.

As for why the warning doesn’t appear on the playground, I assume your local code is using an interface to hide the constructors. If you export the type definitions, then the compiler won’t warn you for not using them, because it’s possible that another module consuming your code is using them even if you aren’t. The playground compiles code without using an interface, so everything is exported.

You can disable the warning for the DxfHeader module by adding @@warning("-37") to the top of it. Example.

2 Likes

Now’s all clear. Thank you for the comprehensive response!

1 Like

Right after I posted that, I noticed: it seems like the functions that @deriving(jsConverter) generates should be sufficient to silence that warning. :thinking: (let insunitsFromJs: int => option<insunits> obviously constructs them.) If you write the equivalent function by hand, then the warning goes away. I wonder if that’s an issue that should be filed with the compiler.

let insunitsFromJs: int => option<insunits> obviously constructs them.

Note the compiler knows the runtime representation so it may skip the indirection to generate an identity function instead.

This does not happen that common, you can use let _ = Unused to disable such warning

1 Like

And I’d have to put such a line for every variant of the type… A single @@warning("-37") is good enough I think :slight_smile: