Help in understanding an error using `ghc-option=-Wunused-top-binds`

G-d willing

Hello,
I have an error when I enable the ghc-option=-Wunused-top-binds under build-options of the daml.yaml file.
I am getting a Defined but not used error on data fields for a data-record. It is very strange, since the specific data record is being used. So why am I getting this error?

Here is the code I am having:

class ProvidesEnv a where
  typeEnv : TypeEnv
  typeEnv = foldl
    (\typEnv (VarSpec ns n t _) -> TM.insert (qualName ns n) t typEnv)
    baseTypeEnv
    (envSpec @a)

  mkEnv : a -> Env
  mkEnv a = foldl
    (\env (VarSpec ns n _ sel) -> TM.insert (qualName ns n) (sel a) env)
    baseEnv
    (envSpec @a)

  envSpec : [VarSpec a]

instance (ProvidesEnv a, ProvidesEnv b) => ProvidesEnv (a, b) where
  envSpec = (contraMap fst <$> envSpec @a) ++ (contraMap snd <$> envSpec @b)
    where contraMap f (VarSpec ns n ft sel) = VarSpec ns n ft $ sel . f

qualName : Optional Text -> Text -> Text
qualName ns n = optional n (\ns -> ns <> "." <> n) ns

addConst : forall a b. (Namespaced a, ToVal b, HasExprType b) => Text -> b -> VarSpec a
addConst n v = addVar n $ const v

addVar : forall a b. (Namespaced a, ToVal b, HasExprType b) => Text -> (a -> b) -> VarSpec a
addVar n sel = VarSpec (namespace @a) n (exprType @b) (toVal . sel)

data VarSpec a = VarSpec with
  ns : Optional Text
  name : Text
  fieldType : ExprType
  selector : a -> Value

and I am getting this error on ns, name, fieldType and selector on the VarSpec data record.

You’re not using the record fields anywhere. Your pattern matches always match on things positionally rather than via the field names.

You have a few different options:

  1. Change at least one of the pattern matches to match on field names.
  2. Add VarSpec(..) to your export list.
  3. Disable the warning at least for this file. You can add {-# OPTIONS -Wno-unused-top-binds #-} at the top of your file for that.

I am not sure I understand what you mean by that.

Also, if you can see, isn’t line 4 is using it?
(\typEnv (VarSpec ns n t _) -> TM.insert (qualName ns n) t typEnv)

Currently you have a positional match, i.e., your match does not care about the field names, it only cares about the order of the arguments.

(\typEnv (VarSpec ns n t _) -> TM.insert (qualName ns n) t typEnv)

If you change it to

(\typEnv (VarSpec with ns = ns, name = n, fieldType = t) -> TM.insert (qualName ns n) t typEnv)

the fields should be used (at least the first 3, for the selector you need to change the match in mkEnv.

G-d willing

First thing first, I had in my export list VarSpec however I did not have it the (..) as you suggested. I tried that and it worked. So, first, can you please explain why adding this (..) made a difference?

Second, I don’t understand the difference between the 2 lines you mentioned in your last reply. I thought that writing: VarSpec ns n t _ is the same as VarSpec with ns = ns, name = n, fieldType = t is the same thing just 2 different ways to create a data record.

Exporting VarSpec only exports the type name but not the constructor or the field selectors. VarSpec(..) exports the type name, the constructor and the field selectors.

You are right that the two lines do the same thing. But one option uses the field names so to the compiler they are used. The other does not, so they are unused. I agree this is a bit quirky. It’s something inherited from Haskell rather than something we added deliberately.

1 Like