Skip to content

Derive instances when data types use type synonyms - #2516

Merged
paf31 merged 3 commits into
masterfrom
phil/derive-with-synonyms
Jan 1, 2017
Merged

paf31 merged 3 commits into
masterfrom
phil/derive-with-synonyms

Conversation

@paf31

@paf31 paf31 commented Dec 31, 2016

Copy link
Copy Markdown
Contributor

Fixes #2481
Fixes #2416
Fixes #1443

I would have liked to fix this by moving deriving into the type checker, but then we'd have to rearrange a whole bunch of stuff, so instead this just uses the externs to build a map of type synonym data, and then reuses the existing replaceAllTypeSynonyms' function to eliminate any synonyms in the instance head.

@garyb garyb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hell yeah! 🎉 🎆 🎊

This approach seems fine to me too, what would have been the advantage of moving it to the typechecker?


-- | Replace fully applied type synonyms
replaceAllTypeSynonyms'
:: M.Map (Qualified (ProperName 'TypeName)) ([(Text, Maybe Kind)], Type)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could move the SynonymMap type into this module, and then use it here?

=> SynonymMap
-> Type
-> m Type
replaceAllTypeSynonymsM syns = either throwError pure . replaceAllTypeSynonyms' syns

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should go in Language.PureScript.TypeChecker.Synonyms too?

-> Declaration
-> m Declaration
deriveInstance mn ds (TypeInstanceDeclaration nm deps className tys@[ty] DerivedInstance)
deriveInstance mn _ ds (TypeInstanceDeclaration nm deps className tys@[ty] DerivedInstance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these need to do synonym substitution too. They inspect data constructor arguments; for example, deriveOrd calls objectType to check for a record.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following fail on 0.10.3:

type L = {}
data X = X L
derive instance eqX :: Eq X

type M = {}
data Y = Y {foo :: M}
derive instance eqY :: Eq Y

type N = {}
data Z = Z N
derive instance eqZ :: Eq Z

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I realized this last night after I finished working on this 😄

I'll try to finish this up later.

@garyb garyb left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Liam's right. Nested synonyms also fail, which is pretty much a necessity to fix it for the record case where it commonly arises:

type Foo = String

type Bar = { foo :: Foo }

type Baz = { baz :: Bar }

newtype T = T Baz

derive instance eqT :: Eq T
derive instance ordT :: Ord T
derive instance genericT :: Generic T

All of the above instances fail, although Newtype works.

edit: example is redundant, since they're covered in Liam's cases... but you get the idea 😉

@paf31
paf31 requested a review from garyb January 1, 2017 00:02
@paf31

paf31 commented Jan 1, 2017

Copy link
Copy Markdown
Contributor Author

This is ready for review again, those issues should now be fixed.

@LiamGoodacre

Copy link
Copy Markdown
Member

Looks good to me 👍

@paf31

paf31 commented Jan 1, 2017

Copy link
Copy Markdown
Contributor Author

Ok, I'll merge this since @LiamGoodacre has signed off and the tests are passing.

@paf31
paf31 merged commit cd535c1 into master Jan 1, 2017
@paf31
paf31 deleted the phil/derive-with-synonyms branch January 1, 2017 00:42
@esad

esad commented Jan 18, 2017

Copy link
Copy Markdown

This still doesn't work for record aliases. I can't get the @garyb example to compile with v0.10.5, it fails with No type class instance was found for Data.Generic.Generic { "baz" :: { "foo" :: String } }.

@paf31

paf31 commented Jan 18, 2017

Copy link
Copy Markdown
Contributor Author

That's a different issue though. It means that we don't derive Generic for nested records (yet).

@esad

esad commented Jan 18, 2017 •

Copy link
Copy Markdown

@paf31 This minimal, non-nested example fails too:

type Baz = { baz :: String }
newtype T = T Baz

derive instance genericT :: Generic T

No type class instance was found for Data.Generic.Generic { "baz" :: String }

@paf31

paf31 commented Jan 18, 2017

Copy link
Copy Markdown
Contributor Author

Then that is a bug, thanks for the report 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

4 participants