danidiaz / by-other-names

Give aliases to record fields

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Improve error messages with TypeErrors

danidiaz opened this issue · comments

Look in A story told by Type Errors for inspiration.

Here's what the GHC User Guide says about them.

Added a type error for mismatched names in db01944, but more could be added.

For example, the error for forgetting to add the alias for the last branch of a sum type is:

    * No instance for (ByOtherNames.AliasTree
                         '[]
                         (M1
                            C
                            ('MetaCons "Ee" 'PrefixI 'False)
                            (S1
                               ('MetaSel
                                  'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy)
                               (Rec0 Int)))
                         '[])

And the error for forgetting to add the alias for the last field of a record type is:

tests\tests.hs:38:5: error:
    * No instance for (ByOtherNames.AliasTree
                         '[]
                         (M1
                            S
                            ('MetaSel
                               ('Just "ee")
                               'NoSourceUnpackedness
                               'NoSourceStrictness
                               'DecidedLazy)
                            (Rec0 Int))
                         '[])

Which could be better.

Added a type error for missing final aliases in 4985c0a.

Other possible errors to improve:

  • Trying to give aliases for records with unnamed fields currently results in:
tests\tests.hs:38:5: error:
    * No instance for (ByOtherNames.AliasTree
                         middle3
                         (M1
                            S
                            ('MetaSel
                               'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy)
                            (Rec0 Bool))
                         middle0)
        arising from a use of `fieldAliases'
  • Trying to give aliases for sum types with named selectors (forbidden in this library) currently results in:
    * No instance for (ByOtherNames.AliasTree
                         '["Bb", "Cc", "Dd", "Ee"]
                         (M1
                            C
                            ('MetaCons "Bb" 'PrefixI 'True)
                            (S1
                               ('MetaSel
                                  ('Just "fofofo")
                                  'NoSourceUnpackedness
                                  'NoSourceStrictness
                                  'DecidedLazy)
                               (Rec0 Bool)))

Sometimes the presence of the functional dependency gets in the way of improving the errors:

These two instances can't coexist:

instance AliasTree before tree '[] => AliasTree before (D1 x (C1 y tree)) '[] where
  parseAliasTree as =
    let (aliases', as') = parseAliasTree as
     in (Record aliases', as')

-- doesn't work because of the functional dependency :(
-- instance ExcessAliasError name => AliasTree before (D1 x (C1 y tree)) (name : names) where

Sometimes the presence of the functional dependency gets in the way of improving the errors

This is even worse in the case of ByOtherNamesH. There, the dependency needs to be bidirectional in order for type inference to work, but it precludes all the custom error messages implemented in ByOtherNames.

type ToAliases :: [(Symbol, [Type])] -> (Type -> Type) -> [(Symbol, [Type])] -> Constraint
-- | The second functional dependency is needed for type inference to work. 
class ToAliases before rep after | before rep -> after, after rep -> before where
  parseAliasTree :: AliasList before a h -> (Aliases rep a h, AliasList after a h)

type ToBranchFields :: [Type] -> (Type -> Type) -> [Type] -> Constraint 
-- | The second functional dependency is needed for type inference to work. 
class ToBranchFields before rep after | before rep -> after, after rep -> before where
  parseBranchFields :: SlotList before h -> (BranchFields rep h, SlotList after h)